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