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