blob: a12cfbea25a934878f0a2ec22b1dfbfe0b0762da [file] [log] [blame]
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -08001/*
2 * Copyright (C) 2017 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 "linker_config.h"
30
31#include "linker_globals.h"
32#include "linker_debug.h"
33#include "linker_utils.h"
34
35#include <android-base/file.h>
Tom Cherryb8ab6182017-04-05 16:20:29 -070036#include <android-base/scopeguard.h>
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -080037#include <android-base/strings.h>
38
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -080039#include <stdlib.h>
40
41#include <string>
42#include <unordered_map>
43
44class ConfigParser {
45 public:
46 enum {
47 kProperty,
48 kSection,
49 kEndOfFile,
50 kError,
51 };
52
53 explicit ConfigParser(std::string&& content)
54 : content_(content), p_(0), lineno_(0), was_end_of_file_(false) {}
55
56 /*
57 * Possible return values
58 * kProperty: name is set to property name and value is set to property value
59 * kSection: name is set to section name.
60 * kEndOfFile: reached end of file.
61 * kError: error_msg is set.
62 */
63 int next_token(std::string* name, std::string* value, std::string* error_msg) {
64 std::string line;
65 while(NextLine(&line)) {
66 size_t found = line.find('#');
67 line = android::base::Trim(line.substr(0, found));
68
69 if (line.empty()) {
70 continue;
71 }
72
73 if (line[0] == '[' && line[line.size() - 1] == ']') {
74 *name = line.substr(1, line.size() - 2);
75 return kSection;
76 }
77
78 found = line.find('=');
79 if (found == std::string::npos) {
80 *error_msg = std::string("invalid format: ") +
81 line +
82 ", expected \"name = property\" or \"[section]\"";
83 return kError;
84 }
85
86 *name = android::base::Trim(line.substr(0, found));
87 *value = android::base::Trim(line.substr(found + 1));
88 return kProperty;
89 }
90
91 // to avoid infinite cycles when programmer makes a mistake
92 CHECK(!was_end_of_file_);
93 was_end_of_file_ = true;
94 return kEndOfFile;
95 }
96
97 size_t lineno() const {
98 return lineno_;
99 }
100
101 private:
102 bool NextLine(std::string* line) {
103 if (p_ == std::string::npos) {
104 return false;
105 }
106
107 size_t found = content_.find('\n', p_);
108 if (found != std::string::npos) {
109 *line = content_.substr(p_, found - p_);
110 p_ = found + 1;
111 } else {
112 *line = content_.substr(p_);
113 p_ = std::string::npos;
114 }
115
116 lineno_++;
117 return true;
118 }
119
120 std::string content_;
121 size_t p_;
122 size_t lineno_;
123 bool was_end_of_file_;
124
125 DISALLOW_IMPLICIT_CONSTRUCTORS(ConfigParser);
126};
127
128class PropertyValue {
129 public:
130 PropertyValue() = default;
131
132 PropertyValue(std::string&& value, size_t lineno)
133 : value_(value), lineno_(lineno) {}
134
135 const std::string& value() const {
136 return value_;
137 }
138
139 size_t lineno() const {
140 return lineno_;
141 }
142
143 private:
144 std::string value_;
145 size_t lineno_;
146};
147
148static std::string create_error_msg(const char* file,
149 size_t lineno,
150 const std::string& msg) {
151 char buf[1024];
152 __libc_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str());
153
154 return std::string(buf);
155}
156
157static bool parse_config_file(const char* ld_config_file_path,
158 const char* binary_realpath,
159 std::unordered_map<std::string, PropertyValue>* properties,
160 std::string* error_msg) {
161 std::string content;
162 if (!android::base::ReadFileToString(ld_config_file_path, &content)) {
163 if (errno != ENOENT) {
164 *error_msg = std::string("error reading file \"") +
165 ld_config_file_path + "\": " + strerror(errno);
166 }
167 return false;
168 }
169
170 ConfigParser cp(std::move(content));
171
172 std::string section_name;
173
174 while(true) {
175 std::string name;
176 std::string value;
177 std::string error;
178
179 int result = cp.next_token(&name, &value, &error);
180 if (result == ConfigParser::kError) {
181 DL_WARN("error parsing %s:%zd: %s (ignoring this line)",
182 ld_config_file_path,
183 cp.lineno(),
184 error.c_str());
185 continue;
186 }
187
188 if (result == ConfigParser::kSection || result == ConfigParser::kEndOfFile) {
189 return false;
190 }
191
192 if (result == ConfigParser::kProperty) {
193 if (!android::base::StartsWith(name, "dir.")) {
194 DL_WARN("error parsing %s:%zd: unexpected property name \"%s\", "
195 "expected format dir.<section_name> (ignoring this line)",
196 ld_config_file_path,
197 cp.lineno(),
198 name.c_str());
199 continue;
200 }
201
202 // remove trailing '/'
203 while (value[value.size() - 1] == '/') {
204 value = value.substr(0, value.size() - 1);
205 }
206
207 if (value.empty()) {
208 DL_WARN("error parsing %s:%zd: property value is empty (ignoring this line)",
209 ld_config_file_path,
210 cp.lineno());
211 continue;
212 }
213
214 if (file_is_under_dir(binary_realpath, value)) {
215 section_name = name.substr(4);
216 break;
217 }
218 }
219 }
220
221 // skip everything until we meet a correct section
222 while (true) {
223 std::string name;
224 std::string value;
225 std::string error;
226
227 int result = cp.next_token(&name, &value, &error);
228
229 if (result == ConfigParser::kSection && name == section_name) {
230 break;
231 }
232
233 if (result == ConfigParser::kEndOfFile) {
234 *error_msg = create_error_msg(ld_config_file_path,
235 cp.lineno(),
236 std::string("section \"") + section_name + "\" not found");
237 return false;
238 }
239 }
240
241 // found the section - parse it
242 while (true) {
243 std::string name;
244 std::string value;
245 std::string error;
246
247 int result = cp.next_token(&name, &value, &error);
248
249 if (result == ConfigParser::kEndOfFile || result == ConfigParser::kSection) {
250 break;
251 }
252
253 if (result == ConfigParser::kProperty) {
254 if (properties->find(name) != properties->end()) {
255 DL_WARN("%s:%zd: warning: property \"%s\" redefinition",
256 ld_config_file_path,
257 cp.lineno(),
258 name.c_str());
259 }
260
261 (*properties)[name] = PropertyValue(std::move(value), cp.lineno());
262 }
263
264 if (result == ConfigParser::kError) {
265 DL_WARN("error parsing %s:%zd: %s (ignoring this line)",
266 ld_config_file_path,
267 cp.lineno(),
268 error.c_str());
269 continue;
270 }
271 }
272
273 return true;
274}
275
276static Config g_config;
277
278static constexpr const char* kDefaultConfigName = "default";
279static constexpr const char* kPropertyAdditionalNamespaces = "additional.namespaces";
280#if defined(__LP64__)
281static constexpr const char* kLibParamValue = "lib64";
282#else
283static constexpr const char* kLibParamValue = "lib";
284#endif
285
286class Properties {
287 public:
288 explicit Properties(std::unordered_map<std::string, PropertyValue>&& properties)
289 : properties_(properties), target_sdk_version_(__ANDROID_API__) {}
290
291 std::vector<std::string> get_strings(const std::string& name, size_t* lineno = nullptr) const {
292 auto it = find_property(name, lineno);
293 if (it == properties_.end()) {
294 // return empty vector
295 return std::vector<std::string>();
296 }
297
298 std::vector<std::string> strings = android::base::Split(it->second.value(), ",");
299
300 for (size_t i = 0; i < strings.size(); ++i) {
301 strings[i] = android::base::Trim(strings[i]);
302 }
303
304 return strings;
305 }
306
307 bool get_bool(const std::string& name, size_t* lineno = nullptr) const {
308 auto it = find_property(name, lineno);
309 if (it == properties_.end()) {
310 return false;
311 }
312
313 return it->second.value() == "true";
314 }
315
316 std::string get_string(const std::string& name, size_t* lineno = nullptr) const {
317 auto it = find_property(name, lineno);
318 return (it == properties_.end()) ? "" : it->second.value();
319 }
320
321 std::vector<std::string> get_paths(const std::string& name, size_t* lineno = nullptr) {
322 std::string paths_str = get_string(name, lineno);
323
324 std::vector<std::string> paths;
325 split_path(paths_str.c_str(), ":", &paths);
326
327 std::vector<std::pair<std::string, std::string>> params;
328 params.push_back({ "LIB", kLibParamValue });
329 if (target_sdk_version_ != 0) {
330 char buf[16];
331 __libc_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_);
332 params.push_back({ "SDK_VER", buf });
333 }
334
335 for (auto&& path : paths) {
336 format_string(&path, params);
337 }
338
339 std::vector<std::string> resolved_paths;
340
341 // do not remove paths that do not exist
342 resolve_paths(paths, &resolved_paths);
343
344 return resolved_paths;
345 }
346
347 void set_target_sdk_version(int target_sdk_version) {
348 target_sdk_version_ = target_sdk_version;
349 }
350
351 private:
352 std::unordered_map<std::string, PropertyValue>::const_iterator
353 find_property(const std::string& name, size_t* lineno) const {
354 auto it = properties_.find(name);
355 if (it != properties_.end() && lineno != nullptr) {
356 *lineno = it->second.lineno();
357 }
358
359 return it;
360 }
361 std::unordered_map<std::string, PropertyValue> properties_;
362 int target_sdk_version_;
363
364 DISALLOW_IMPLICIT_CONSTRUCTORS(Properties);
365};
366
367bool Config::read_binary_config(const char* ld_config_file_path,
368 const char* binary_realpath,
369 bool is_asan,
370 const Config** config,
371 std::string* error_msg) {
372 g_config.clear();
373
374 std::unordered_map<std::string, PropertyValue> property_map;
375 if (!parse_config_file(ld_config_file_path, binary_realpath, &property_map, error_msg)) {
376 return false;
377 }
378
379 Properties properties(std::move(property_map));
380
Tom Cherryb8ab6182017-04-05 16:20:29 -0700381 auto failure_guard = android::base::make_scope_guard([] { g_config.clear(); });
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -0800382
383 std::unordered_map<std::string, NamespaceConfig*> namespace_configs;
384
385 namespace_configs[kDefaultConfigName] = g_config.create_namespace_config(kDefaultConfigName);
386
387 std::vector<std::string> additional_namespaces = properties.get_strings(kPropertyAdditionalNamespaces);
388 for (const auto& name : additional_namespaces) {
389 namespace_configs[name] = g_config.create_namespace_config(name);
390 }
391
392 bool versioning_enabled = properties.get_bool("enable.target.sdk.version");
393 int target_sdk_version = __ANDROID_API__;
394 if (versioning_enabled) {
395 std::string version_file = dirname(binary_realpath) + "/.version";
396 std::string content;
397 if (!android::base::ReadFileToString(version_file, &content)) {
398 if (errno != ENOENT) {
399 *error_msg = std::string("error reading version file \"") +
400 version_file + "\": " + strerror(errno);
401 return false;
402 }
403 } else {
404 content = android::base::Trim(content);
405 errno = 0;
406 char* end = nullptr;
407 const char* content_str = content.c_str();
408 int result = strtol(content_str, &end, 10);
409 if (errno == 0 && *end == '\0' && result > 0) {
410 target_sdk_version = result;
411 properties.set_target_sdk_version(target_sdk_version);
412 } else {
413 *error_msg = std::string("invalid version \"") + version_file + "\": \"" + content +"\"";
414 return false;
415 }
416 }
417 }
418
419 g_config.set_target_sdk_version(target_sdk_version);
420
421 for (auto ns_config_it : namespace_configs) {
422 auto& name = ns_config_it.first;
423 NamespaceConfig* ns_config = ns_config_it.second;
424
425 std::string property_name_prefix = std::string("namespace.") + name;
426
427 size_t lineno = 0;
428 std::vector<std::string> linked_namespaces =
429 properties.get_strings(property_name_prefix + ".links", &lineno);
430
431 for (const auto& linked_ns_name : linked_namespaces) {
432 if (namespace_configs.find(linked_ns_name) == namespace_configs.end()) {
433 *error_msg = create_error_msg(ld_config_file_path,
434 lineno,
435 std::string("undefined namespace: ") + linked_ns_name);
436 return false;
437 }
438
439 std::string shared_libs = properties.get_string(property_name_prefix +
440 ".link." +
441 linked_ns_name +
442 ".shared_libs", &lineno);
443
444 if (shared_libs.empty()) {
445 *error_msg = create_error_msg(ld_config_file_path,
446 lineno,
447 std::string("list of shared_libs for ") +
448 name +
449 "->" +
450 linked_ns_name +
451 " link is not specified or is empty.");
452 return false;
453 }
454
455 ns_config->add_namespace_link(linked_ns_name, shared_libs);
456 }
457
458 ns_config->set_isolated(properties.get_bool(property_name_prefix + ".isolated"));
459
460 // these are affected by is_asan flag
461 if (is_asan) {
462 property_name_prefix += ".asan";
463 }
464
465 ns_config->set_search_paths(properties.get_paths(property_name_prefix + ".search.paths"));
466 ns_config->set_permitted_paths(properties.get_paths(property_name_prefix + ".permitted.paths"));
467 }
468
Tom Cherryb8ab6182017-04-05 16:20:29 -0700469 failure_guard.Disable();
Dimitry Ivanov4cabfaa2017-03-07 11:19:05 -0800470 *config = &g_config;
471 return true;
472}
473
474NamespaceConfig* Config::create_namespace_config(const std::string& name) {
475 namespace_configs_.push_back(std::unique_ptr<NamespaceConfig>(new NamespaceConfig(name)));
476 NamespaceConfig* ns_config_ptr = namespace_configs_.back().get();
477 namespace_configs_map_[name] = ns_config_ptr;
478 return ns_config_ptr;
479}
480
481void Config::clear() {
482 namespace_configs_.clear();
483 namespace_configs_map_.clear();
484}