blob: 885542e1e4555b27924e388fce91f6a6915beb42 [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
40#include <sys/system_properties.h>
41
42#include <private/bionic_macros.h>
43
44#include "Config.h"
45#include "debug_log.h"
46
Christopher Ferris549e5222016-02-22 19:23:26 -080047// Config constants
48static constexpr uint8_t DEFAULT_FILL_ALLOC_VALUE = 0xeb;
49static constexpr uint8_t DEFAULT_FILL_FREE_VALUE = 0xef;
50
51static constexpr uint8_t DEFAULT_FRONT_GUARD_VALUE = 0xaa;
52static constexpr uint8_t DEFAULT_REAR_GUARD_VALUE = 0xbb;
53
54// Used as the default for all guard values.
55static constexpr size_t DEFAULT_GUARD_BYTES = 32;
56static constexpr size_t MAX_GUARD_BYTES = 16384;
57
58static constexpr size_t DEFAULT_BACKTRACE_FRAMES = 16;
59static constexpr size_t MAX_BACKTRACE_FRAMES = 256;
60
61static constexpr size_t DEFAULT_EXPAND_BYTES = 16;
62static constexpr size_t MAX_EXPAND_BYTES = 16384;
63
64static constexpr size_t DEFAULT_FREE_TRACK_ALLOCATIONS = 100;
65static constexpr size_t MAX_FREE_TRACK_ALLOCATIONS = 16384;
66
Christopher Ferris7bd01782016-04-20 12:30:58 -070067static constexpr size_t DEFAULT_RECORD_ALLOCS = 8000000;
68static constexpr size_t MAX_RECORD_ALLOCS = 50000000;
69static constexpr const char DEFAULT_RECORD_ALLOCS_FILE[] = "/data/local/tmp/record_allocs.txt";
Christopher Ferris63860cb2015-11-16 17:30:32 -080070
Christopher Ferris7bd01782016-04-20 12:30:58 -070071struct Option {
72 Option(std::string name, uint64_t option, bool combo_option = false, bool* config = nullptr)
73 : name(name), option(option), combo_option(combo_option), config(config) {}
74 virtual ~Option() = default;
75
76 std::string name;
77
78 uint64_t option;
Christopher Ferris63860cb2015-11-16 17:30:32 -080079 // If set to true, then all of the options following are set on until
Christopher Ferris7bd01782016-04-20 12:30:58 -070080 // the combo_option value is set to false.
Christopher Ferris63860cb2015-11-16 17:30:32 -080081 bool combo_option = false;
Christopher Ferris7bd01782016-04-20 12:30:58 -070082 bool* config;
83
84 virtual bool ParseValue(const std::string& option_name, const std::string& value) const;
85
86 virtual void SetDefault() const { }
Christopher Ferris63860cb2015-11-16 17:30:32 -080087};
88
Christopher Ferris7bd01782016-04-20 12:30:58 -070089bool Option::ParseValue(const std::string& option_name, const std::string& raw_value) const {
90 if (!raw_value.empty()) {
91 error_log("%s: value set for option '%s' which does not take a value",
92 getprogname(), option_name.c_str());
93 return false;
94 }
95 return true;
96}
97
98struct OptionString : public Option {
99 OptionString(std::string name, uint64_t option, std::string default_value,
100 std::string* value, bool combo_option = false,
101 bool* config = nullptr)
102 : Option(name, option, combo_option, config), default_value(default_value), value(value) {}
103 virtual ~OptionString() = default;
104
105 std::string default_value;
106 std::string* value;
107
108 bool ParseValue(const std::string& option_name, const std::string& value) const override;
109
110 void SetDefault() const override { if (value) *value = default_value; }
111};
112
113bool OptionString::ParseValue(const std::string&, const std::string& raw_value) const {
114 if (!raw_value.empty()) {
115 *value = raw_value;
116 }
117 return true;
118}
119
120struct OptionSizeT : public Option {
121 OptionSizeT(std::string name, size_t default_value, size_t min_value, size_t max_value,
122 uint64_t option, size_t* value, bool combo_option = false, bool* config = nullptr)
123 : Option(name, option, combo_option, config), default_value(default_value),
124 min_value(min_value), max_value(max_value), value(value) {}
125 virtual ~OptionSizeT() = default;
126
127 size_t default_value;
128 size_t min_value;
129 size_t max_value;
130
131 size_t* value;
132
133 bool ParseValue(const std::string& option_name, const std::string& value) const override;
134
135 void SetDefault() const override { if (value) *value = default_value; }
136};
137
138bool OptionSizeT::ParseValue(const std::string& option_name, const std::string& raw_value) const {
139 if (raw_value.empty()) {
140 // Value should have been set by the SetDefault() pass.
141 return true;
142 }
143
144 // Parse the value into a size_t value.
145 errno = 0;
146 char* end;
147 long parsed_value = strtol(raw_value.c_str(), &end, 10);
148 if (errno != 0) {
149 error_log("%s: bad value for option '%s': %s", getprogname(), option_name.c_str(),
150 strerror(errno));
151 return false;
152 }
153 if (end == raw_value.c_str()) {
154 error_log("%s: bad value for option '%s'", getprogname(), option_name.c_str());
155 return false;
156 }
157 if (static_cast<size_t>(end - raw_value.c_str()) != raw_value.size()) {
158 error_log("%s: bad value for option '%s', non space found after option: %s",
159 getprogname(), option_name.c_str(), end);
160 return false;
161 }
162 if (parsed_value < 0) {
163 error_log("%s: bad value for option '%s', value cannot be negative: %ld",
164 getprogname(), option_name.c_str(), parsed_value);
165 return false;
166 }
167
168 if (static_cast<size_t>(parsed_value) < min_value) {
169 error_log("%s: bad value for option '%s', value must be >= %zu: %ld",
170 getprogname(), option_name.c_str(), min_value, parsed_value);
171 return false;
172 }
173 if (static_cast<size_t>(parsed_value) > max_value) {
174 error_log("%s: bad value for option '%s', value must be <= %zu: %ld",
175 getprogname(), option_name.c_str(), max_value, parsed_value);
176 return false;
177 }
178 *value = static_cast<size_t>(parsed_value);
179 return true;
180}
181
Christopher Ferris63860cb2015-11-16 17:30:32 -0800182class PropertyParser {
183 public:
Chih-Hung Hsieh62e3a072016-05-03 12:08:05 -0700184 explicit PropertyParser(const char* property) : cur_(property) {}
Christopher Ferris63860cb2015-11-16 17:30:32 -0800185
Christopher Ferris7bd01782016-04-20 12:30:58 -0700186 bool Get(std::string* property, std::string* value);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800187
188 bool Done() { return done_; }
189
190 void LogUsage();
191
Christopher Ferris63860cb2015-11-16 17:30:32 -0800192 private:
193 const char* cur_ = nullptr;
194
195 bool done_ = false;
196
197 DISALLOW_COPY_AND_ASSIGN(PropertyParser);
198};
199
Christopher Ferris7bd01782016-04-20 12:30:58 -0700200bool PropertyParser::Get(std::string* property, std::string* value) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800201 // Process each property name we can find.
202 while (isspace(*cur_))
203 ++cur_;
204
205 if (*cur_ == '\0') {
206 done_ = true;
207 return false;
208 }
209
Christopher Ferris7bd01782016-04-20 12:30:58 -0700210 const char* start = cur_;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800211 while (!isspace(*cur_) && *cur_ != '=' && *cur_ != '\0')
212 ++cur_;
213
Christopher Ferris7bd01782016-04-20 12:30:58 -0700214 *property = std::string(start, cur_ - start);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800215
216 // Skip any spaces after the name.
Christopher Ferris7bd01782016-04-20 12:30:58 -0700217 while (isspace(*cur_))
Christopher Ferris63860cb2015-11-16 17:30:32 -0800218 ++cur_;
219
Christopher Ferris7bd01782016-04-20 12:30:58 -0700220 value->clear();
Christopher Ferris63860cb2015-11-16 17:30:32 -0800221 if (*cur_ == '=') {
222 ++cur_;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700223 // Skip the space after the equal.
224 while (isspace(*cur_))
225 ++cur_;
226
227 start = cur_;
228 while (!isspace(*cur_) && *cur_ != '\0')
229 ++cur_;
230
231 if (cur_ != start) {
232 *value = std::string(start, cur_ - start);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800233 }
Christopher Ferris63860cb2015-11-16 17:30:32 -0800234 }
235 return true;
236}
237
238void PropertyParser::LogUsage() {
239 error_log("malloc debug options usage:");
240 error_log("");
241 error_log(" front_guard[=XX]");
242 error_log(" Enables a front guard on all allocations. If XX is set");
243 error_log(" it sets the number of bytes in the guard. The default is");
Christopher Ferris549e5222016-02-22 19:23:26 -0800244 error_log(" %zu bytes, the max bytes is %zu.", DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800245 error_log("");
246 error_log(" rear_guard[=XX]");
247 error_log(" Enables a rear guard on all allocations. If XX is set");
248 error_log(" it sets the number of bytes in the guard. The default is");
Christopher Ferris549e5222016-02-22 19:23:26 -0800249 error_log(" %zu bytes, the max bytes is %zu.", DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800250 error_log("");
251 error_log(" guard[=XX]");
252 error_log(" Enables both a front guard and a rear guard on all allocations.");
253 error_log(" If XX is set it sets the number of bytes in both guards.");
Christopher Ferris549e5222016-02-22 19:23:26 -0800254 error_log(" The default is %zu bytes, the max bytes is %zu.",
255 DEFAULT_GUARD_BYTES, MAX_GUARD_BYTES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800256 error_log("");
257 error_log(" backtrace[=XX]");
258 error_log(" Enable capturing the backtrace at the point of allocation.");
259 error_log(" If XX is set it sets the number of backtrace frames.");
Christopher Ferris549e5222016-02-22 19:23:26 -0800260 error_log(" The default is %zu frames, the max number of frames is %zu.",
261 DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800262 error_log("");
263 error_log(" backtrace_enable_on_signal[=XX]");
264 error_log(" Enable capturing the backtrace at the point of allocation.");
265 error_log(" The backtrace capture is not enabled until the process");
266 error_log(" receives a signal. If XX is set it sets the number of backtrace");
Christopher Ferris549e5222016-02-22 19:23:26 -0800267 error_log(" frames. The default is %zu frames, the max number of frames is %zu.",
268 DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800269 error_log("");
270 error_log(" fill_on_alloc[=XX]");
271 error_log(" On first allocation, fill with the value 0x%02x.", DEFAULT_FILL_ALLOC_VALUE);
272 error_log(" If XX is set it will only fill up to XX bytes of the");
273 error_log(" allocation. The default is to fill the entire allocation.");
274 error_log("");
275 error_log(" fill_on_free[=XX]");
276 error_log(" On free, fill with the value 0x%02x. If XX is set it will",
277 DEFAULT_FILL_FREE_VALUE);
278 error_log(" only fill up to XX bytes of the allocation. The default is to");
279 error_log(" fill the entire allocation.");
280 error_log("");
281 error_log(" fill[=XX]");
282 error_log(" On both first allocation free, fill with the value 0x%02x on",
283 DEFAULT_FILL_ALLOC_VALUE);
284 error_log(" first allocation and the value 0x%02x. If XX is set, only fill",
285 DEFAULT_FILL_FREE_VALUE);
286 error_log(" up to XX bytes. The default is to fill the entire allocation.");
287 error_log("");
288 error_log(" expand_alloc[=XX]");
289 error_log(" Allocate an extra number of bytes for every allocation call.");
290 error_log(" If XX is set, that is the number of bytes to expand the");
Christopher Ferris549e5222016-02-22 19:23:26 -0800291 error_log(" allocation by. The default is %zu bytes, the max bytes is %zu.",
292 DEFAULT_EXPAND_BYTES, MAX_EXPAND_BYTES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800293 error_log("");
294 error_log(" free_track[=XX]");
295 error_log(" When a pointer is freed, do not free the memory right away.");
296 error_log(" Instead, keep XX of these allocations around and then verify");
297 error_log(" that they have not been modified when the total number of freed");
298 error_log(" allocations exceeds the XX amount. When the program terminates,");
Christopher Ferris7993b802016-01-28 18:35:05 -0800299 error_log(" the rest of these allocations are verified. When this option is");
300 error_log(" enabled, it automatically records the backtrace at the time of the free.");
Christopher Ferris549e5222016-02-22 19:23:26 -0800301 error_log(" The default is to record %zu allocations, the max allocations",
302 DEFAULT_FREE_TRACK_ALLOCATIONS);
303 error_log(" to record is %zu.", MAX_FREE_TRACK_ALLOCATIONS);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800304 error_log("");
Christopher Ferris7993b802016-01-28 18:35:05 -0800305 error_log(" free_track_backtrace_num_frames[=XX]");
306 error_log(" This option only has meaning if free_track is set. This indicates");
307 error_log(" how many backtrace frames to capture when an allocation is freed.");
308 error_log(" If XX is set, that is the number of frames to capture. If XX");
309 error_log(" is set to zero, then no backtrace will be captured.");
Christopher Ferris549e5222016-02-22 19:23:26 -0800310 error_log(" The default is to record %zu frames, the max number of frames is %zu.",
311 DEFAULT_BACKTRACE_FRAMES, MAX_BACKTRACE_FRAMES);
Christopher Ferris7993b802016-01-28 18:35:05 -0800312 error_log("");
Christopher Ferris63860cb2015-11-16 17:30:32 -0800313 error_log(" leak_track");
314 error_log(" Enable the leak tracking of memory allocations.");
Christopher Ferris7bd01782016-04-20 12:30:58 -0700315 error_log("");
316 error_log(" record_allocs[=XX]");
317 error_log(" Record every single allocation/free call. When a specific signal");
318 error_log(" is sent to the process, the contents of recording are written to");
319 error_log(" a file (%s) and the recording is cleared.", DEFAULT_RECORD_ALLOCS_FILE);
320 error_log(" If XX is set, that is the total number of allocations/frees that can");
321 error_log(" recorded. of frames to capture. The default value is %zu.", DEFAULT_RECORD_ALLOCS);
322 error_log(" If the allocation list fills up, all further allocations are not recorded.");
323 error_log("");
324 error_log(" record_alloc_file[=FILE]");
325 error_log(" This option only has meaning if the record_allocs options has been specified.");
326 error_log(" This is the name of the file to which recording information will be dumped.");
327 error_log(" The default is %s.", DEFAULT_RECORD_ALLOCS_FILE);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800328}
329
330// This function is designed to be called once. A second call will not
331// reset all variables.
332bool Config::SetFromProperties() {
333 char property_str[PROP_VALUE_MAX];
334 memset(property_str, 0, sizeof(property_str));
335 if (!__system_property_get("libc.debug.malloc.options", property_str)) {
336 return false;
337 }
338
339 // Initialize a few default values.
Christopher Ferris549e5222016-02-22 19:23:26 -0800340 fill_alloc_value = DEFAULT_FILL_ALLOC_VALUE;
341 fill_free_value = DEFAULT_FILL_FREE_VALUE;
342 front_guard_value = DEFAULT_FRONT_GUARD_VALUE;
343 rear_guard_value = DEFAULT_REAR_GUARD_VALUE;
Christopher Ferrisea26b332016-04-15 14:13:52 -0700344 backtrace_signal = SIGRTMAX - 19;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700345 record_allocs_signal = SIGRTMAX - 18;
346 free_track_backtrace_num_frames = 0;
347 record_allocs_file.clear();
Christopher Ferris63860cb2015-11-16 17:30:32 -0800348
349 // Parse the options are of the format:
350 // option_name or option_name=XX
351
Christopher Ferris7bd01782016-04-20 12:30:58 -0700352 // Supported options:
353 const OptionSizeT option_guard(
354 "guard", DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, 0, nullptr, true);
355 // Enable front guard. Value is the size of the guard.
356 const OptionSizeT option_front_guard(
357 "front_guard", DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, FRONT_GUARD,
358 &this->front_guard_bytes, true);
359 // Enable end guard. Value is the size of the guard.
360 const OptionSizeT option_rear_guard(
361 "rear_guard", DEFAULT_GUARD_BYTES, 1, MAX_GUARD_BYTES, REAR_GUARD, &this->rear_guard_bytes,
362 true);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800363
Christopher Ferris7bd01782016-04-20 12:30:58 -0700364 // Enable logging the backtrace on allocation. Value is the total
365 // number of frames to log.
366 const OptionSizeT option_backtrace(
367 "backtrace", DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES, BACKTRACE | TRACK_ALLOCS,
368 &this->backtrace_frames, false, &this->backtrace_enabled);
369 // Enable gathering backtrace values on a signal.
370 const OptionSizeT option_backtrace_enable_on_signal(
371 "backtrace_enable_on_signal", DEFAULT_BACKTRACE_FRAMES, 1, MAX_BACKTRACE_FRAMES,
372 BACKTRACE | TRACK_ALLOCS, &this->backtrace_frames, false, &this->backtrace_enable_on_signal);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800373
Christopher Ferris7bd01782016-04-20 12:30:58 -0700374 const OptionSizeT option_fill("fill", SIZE_MAX, 1, SIZE_MAX, 0, nullptr, true);
375 // Fill the allocation with an arbitrary pattern on allocation.
376 // Value is the number of bytes of the allocation to fill
377 // (default entire allocation).
378 const OptionSizeT option_fill_on_alloc(
379 "fill_on_alloc", SIZE_MAX, 1, SIZE_MAX, FILL_ON_ALLOC, &this->fill_on_alloc_bytes, true);
380 // Fill the allocation with an arbitrary pattern on free.
381 // Value is the number of bytes of the allocation to fill
382 // (default entire allocation).
383 const OptionSizeT option_fill_on_free(
384 "fill_on_free", SIZE_MAX, 1, SIZE_MAX, FILL_ON_FREE, &this->fill_on_free_bytes, true);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800385
Christopher Ferris7bd01782016-04-20 12:30:58 -0700386 // Expand the size of every alloc by this number bytes. Value is
387 // the total number of bytes to expand every allocation by.
388 const OptionSizeT option_expand_alloc(
389 "expand_alloc", DEFAULT_EXPAND_BYTES, 1, MAX_EXPAND_BYTES, EXPAND_ALLOC,
390 &this->expand_alloc_bytes);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800391
Christopher Ferris7bd01782016-04-20 12:30:58 -0700392 // Keep track of the freed allocations and verify at a later date
393 // that they have not been used. Turning this on, also turns on
394 // fill on free.
395 const OptionSizeT option_free_track(
396 "free_track", DEFAULT_FREE_TRACK_ALLOCATIONS, 1, MAX_FREE_TRACK_ALLOCATIONS,
397 FREE_TRACK | FILL_ON_FREE, &this->free_track_allocations);
398 // Number of backtrace frames to keep when free_track is enabled. If this
399 // value is set to zero, no backtrace will be kept.
400 const OptionSizeT option_free_track_backtrace_num_frames(
401 "free_track_backtrace_num_frames", DEFAULT_BACKTRACE_FRAMES, 0, MAX_BACKTRACE_FRAMES, 0,
402 &this->free_track_backtrace_num_frames);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800403
Christopher Ferris7bd01782016-04-20 12:30:58 -0700404 // Enable printing leaked allocations.
405 const Option option_leak_track("leak_track", LEAK_TRACK | TRACK_ALLOCS);
406
407 const OptionSizeT option_record_allocs(
408 "record_allocs", DEFAULT_RECORD_ALLOCS, 1, MAX_RECORD_ALLOCS, RECORD_ALLOCS,
409 &this->record_allocs_num_entries);
410 const OptionString option_record_allocs_file(
411 "record_allocs_file", 0, DEFAULT_RECORD_ALLOCS_FILE, &this->record_allocs_file);
412
413 const Option* option_list[] = {
414 &option_guard, &option_front_guard, &option_rear_guard,
415 &option_backtrace, &option_backtrace_enable_on_signal,
416 &option_fill, &option_fill_on_alloc, &option_fill_on_free,
417 &option_expand_alloc,
418 &option_free_track, &option_free_track_backtrace_num_frames,
419 &option_leak_track,
420 &option_record_allocs, &option_record_allocs_file,
Christopher Ferris63860cb2015-11-16 17:30:32 -0800421 };
422
Christopher Ferris7bd01782016-04-20 12:30:58 -0700423 // Set defaults for all of the options.
424 for (size_t i = 0; i < sizeof(option_list)/sizeof(Option*); i++) {
425 option_list[i]->SetDefault();
426 }
427
Christopher Ferris63860cb2015-11-16 17:30:32 -0800428 // Process each property name we can find.
Christopher Ferris63860cb2015-11-16 17:30:32 -0800429 PropertyParser parser(property_str);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800430 bool valid = true;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700431 std::string property;
432 std::string value;
433 while (valid && parser.Get(&property, &value)) {
Christopher Ferrisa4b14252016-03-14 15:29:46 -0700434 bool found = false;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700435 for (size_t i = 0; i < sizeof(option_list)/sizeof(Option*); i++) {
436 if (property == option_list[i]->name) {
437 if (option_list[i]->option == 0 && option_list[i]->combo_option) {
438 const std::string* option_name = &option_list[i]->name;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800439 i++;
Christopher Ferris7bd01782016-04-20 12:30:58 -0700440 for (; i < sizeof(option_list)/sizeof(Option*) && option_list[i]->combo_option; i++) {
441 if (!option_list[i]->ParseValue(*option_name, value)) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800442 valid = false;
443 break;
444 }
Christopher Ferris7bd01782016-04-20 12:30:58 -0700445 if (option_list[i]->config) {
446 *option_list[i]->config = true;
447 }
448 options |= option_list[i]->option;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800449 }
450 if (!valid) {
451 break;
452 }
453 } else {
Christopher Ferris7bd01782016-04-20 12:30:58 -0700454 if (!option_list[i]->ParseValue(option_list[i]->name, value)) {
Christopher Ferris63860cb2015-11-16 17:30:32 -0800455 valid = false;
456 break;
457 }
Christopher Ferris7bd01782016-04-20 12:30:58 -0700458 if (option_list[i]->config) {
459 *option_list[i]->config = true;
460 }
461 options |= option_list[i]->option;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800462 }
463 found = true;
464 break;
465 }
466 }
467 if (valid && !found) {
468 error_log("%s: unknown option %s", getprogname(), property.c_str());
469 valid = false;
470 break;
471 }
472 }
473
474 valid = valid && parser.Done();
475
476 if (valid) {
Christopher Ferris72df6702016-02-11 15:51:31 -0800477 // It's necessary to align the front guard to MINIMUM_ALIGNMENT_BYTES to
Christopher Ferris63860cb2015-11-16 17:30:32 -0800478 // make sure that the header is aligned properly.
479 if (options & FRONT_GUARD) {
Christopher Ferris72df6702016-02-11 15:51:31 -0800480 front_guard_bytes = BIONIC_ALIGN(front_guard_bytes, MINIMUM_ALIGNMENT_BYTES);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800481 }
Christopher Ferris63860cb2015-11-16 17:30:32 -0800482 } else {
483 parser.LogUsage();
484 }
485
486 return valid;
487}