2 * Copyright (C) 2017 The Android Open Source Project
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
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
29 #include "linker_config.h"
31 #include "linker_globals.h"
32 #include "linker_debug.h"
33 #include "linker_utils.h"
35 #include <android-base/file.h>
36 #include <android-base/scopeguard.h>
37 #include <android-base/strings.h>
39 #include <async_safe/log.h>
44 #include <unordered_map>
55 explicit ConfigParser(std::string&& content)
56 : content_(content), p_(0), lineno_(0), was_end_of_file_(false) {}
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.
65 int next_token(std::string* name, std::string* value, std::string* error_msg) {
67 while(NextLine(&line)) {
68 size_t found = line.find('#');
69 line = android::base::Trim(line.substr(0, found));
75 if (line[0] == '[' && line[line.size() - 1] == ']') {
76 *name = line.substr(1, line.size() - 2);
80 found = line.find('=');
81 if (found == std::string::npos) {
82 *error_msg = std::string("invalid format: ") +
84 ", expected \"name = property\" or \"[section]\"";
88 *name = android::base::Trim(line.substr(0, found));
89 *value = android::base::Trim(line.substr(found + 1));
93 // to avoid infinite cycles when programmer makes a mistake
94 CHECK(!was_end_of_file_);
95 was_end_of_file_ = true;
99 size_t lineno() const {
104 bool NextLine(std::string* line) {
105 if (p_ == std::string::npos) {
109 size_t found = content_.find('\n', p_);
110 if (found != std::string::npos) {
111 *line = content_.substr(p_, found - p_);
114 *line = content_.substr(p_);
115 p_ = std::string::npos;
122 std::string content_;
125 bool was_end_of_file_;
127 DISALLOW_IMPLICIT_CONSTRUCTORS(ConfigParser);
130 class PropertyValue {
132 PropertyValue() = default;
134 PropertyValue(std::string&& value, size_t lineno)
135 : value_(value), lineno_(lineno) {}
137 const std::string& value() const {
141 size_t lineno() const {
150 static std::string create_error_msg(const char* file,
152 const std::string& msg) {
154 async_safe_format_buffer(buf, sizeof(buf), "%s:%zu: error: %s", file, lineno, msg.c_str());
156 return std::string(buf);
159 static 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) {
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);
172 ConfigParser cp(std::move(content));
174 std::string section_name;
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)",
190 if (result == ConfigParser::kSection || result == ConfigParser::kEndOfFile) {
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)",
204 // remove trailing '/'
205 while (value[value.size() - 1] == '/') {
206 value = value.substr(0, value.size() - 1);
210 DL_WARN("error parsing %s:%zd: property value is empty (ignoring this line)",
216 if (file_is_under_dir(binary_realpath, value)) {
217 section_name = name.substr(4);
223 // skip everything until we meet a correct section
229 int result = cp.next_token(&name, &value, &error);
231 if (result == ConfigParser::kSection && name == section_name) {
235 if (result == ConfigParser::kEndOfFile) {
236 *error_msg = create_error_msg(ld_config_file_path,
238 std::string("section \"") + section_name + "\" not found");
243 // found the section - parse it
249 int result = cp.next_token(&name, &value, &error);
251 if (result == ConfigParser::kEndOfFile || result == ConfigParser::kSection) {
255 if (result == ConfigParser::kProperty) {
256 if (properties->find(name) != properties->end()) {
257 DL_WARN("%s:%zd: warning: property \"%s\" redefinition",
263 (*properties)[name] = PropertyValue(std::move(value), cp.lineno());
266 if (result == ConfigParser::kError) {
267 DL_WARN("error parsing %s:%zd: %s (ignoring this line)",
278 static Config g_config;
280 static constexpr const char* kDefaultConfigName = "default";
281 static constexpr const char* kPropertyAdditionalNamespaces = "additional.namespaces";
282 #if defined(__LP64__)
283 static constexpr const char* kLibParamValue = "lib64";
285 static constexpr const char* kLibParamValue = "lib";
290 explicit Properties(std::unordered_map<std::string, PropertyValue>&& properties)
291 : properties_(properties), target_sdk_version_(__ANDROID_API__) {}
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>();
300 std::vector<std::string> strings = android::base::Split(it->second.value(), ",");
302 for (size_t i = 0; i < strings.size(); ++i) {
303 strings[i] = android::base::Trim(strings[i]);
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()) {
315 return it->second.value() == "true";
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();
323 std::vector<std::string> get_paths(const std::string& name, size_t* lineno = nullptr) {
324 std::string paths_str = get_string(name, lineno);
326 std::vector<std::string> paths;
327 split_path(paths_str.c_str(), ":", &paths);
329 std::vector<std::pair<std::string, std::string>> params;
330 params.push_back({ "LIB", kLibParamValue });
331 if (target_sdk_version_ != 0) {
333 async_safe_format_buffer(buf, sizeof(buf), "%d", target_sdk_version_);
334 params.push_back({ "SDK_VER", buf });
337 for (auto&& path : paths) {
338 format_string(&path, params);
341 std::vector<std::string> resolved_paths;
343 // do not remove paths that do not exist
344 resolve_paths(paths, &resolved_paths);
346 return resolved_paths;
349 void set_target_sdk_version(int target_sdk_version) {
350 target_sdk_version_ = target_sdk_version;
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();
363 std::unordered_map<std::string, PropertyValue> properties_;
364 int target_sdk_version_;
366 DISALLOW_IMPLICIT_CONSTRUCTORS(Properties);
369 bool Config::read_binary_config(const char* ld_config_file_path,
370 const char* binary_realpath,
372 const Config** config,
373 std::string* error_msg) {
374 // TODO(b/38114603) Currently, multiple namespaces does not support ASAN mode
375 // where some symbols should be intercepted via LD_PRELOAD; LD_PRELOADed libs
376 // are not being preloaded into the linked namespaces other than the default
377 // namespace. Until we fix the problem, we temporarily disable ld.config.txt
385 std::unordered_map<std::string, PropertyValue> property_map;
386 if (!parse_config_file(ld_config_file_path, binary_realpath, &property_map, error_msg)) {
390 Properties properties(std::move(property_map));
392 auto failure_guard = android::base::make_scope_guard([] { g_config.clear(); });
394 std::unordered_map<std::string, NamespaceConfig*> namespace_configs;
396 namespace_configs[kDefaultConfigName] = g_config.create_namespace_config(kDefaultConfigName);
398 std::vector<std::string> additional_namespaces = properties.get_strings(kPropertyAdditionalNamespaces);
399 for (const auto& name : additional_namespaces) {
400 namespace_configs[name] = g_config.create_namespace_config(name);
403 bool versioning_enabled = properties.get_bool("enable.target.sdk.version");
404 int target_sdk_version = __ANDROID_API__;
405 if (versioning_enabled) {
406 std::string version_file = dirname(binary_realpath) + "/.version";
408 if (!android::base::ReadFileToString(version_file, &content)) {
409 if (errno != ENOENT) {
410 *error_msg = std::string("error reading version file \"") +
411 version_file + "\": " + strerror(errno);
415 content = android::base::Trim(content);
418 const char* content_str = content.c_str();
419 int result = strtol(content_str, &end, 10);
420 if (errno == 0 && *end == '\0' && result > 0) {
421 target_sdk_version = result;
422 properties.set_target_sdk_version(target_sdk_version);
424 *error_msg = std::string("invalid version \"") + version_file + "\": \"" + content +"\"";
430 g_config.set_target_sdk_version(target_sdk_version);
432 for (auto ns_config_it : namespace_configs) {
433 auto& name = ns_config_it.first;
434 NamespaceConfig* ns_config = ns_config_it.second;
436 std::string property_name_prefix = std::string("namespace.") + name;
439 std::vector<std::string> linked_namespaces =
440 properties.get_strings(property_name_prefix + ".links", &lineno);
442 for (const auto& linked_ns_name : linked_namespaces) {
443 if (namespace_configs.find(linked_ns_name) == namespace_configs.end()) {
444 *error_msg = create_error_msg(ld_config_file_path,
446 std::string("undefined namespace: ") + linked_ns_name);
450 std::string shared_libs = properties.get_string(property_name_prefix +
453 ".shared_libs", &lineno);
455 if (shared_libs.empty()) {
456 *error_msg = create_error_msg(ld_config_file_path,
458 std::string("list of shared_libs for ") +
462 " link is not specified or is empty.");
466 ns_config->add_namespace_link(linked_ns_name, shared_libs);
469 ns_config->set_isolated(properties.get_bool(property_name_prefix + ".isolated"));
470 ns_config->set_visible(properties.get_bool(property_name_prefix + ".visible"));
472 // these are affected by is_asan flag
474 property_name_prefix += ".asan";
477 ns_config->set_search_paths(properties.get_paths(property_name_prefix + ".search.paths"));
478 ns_config->set_permitted_paths(properties.get_paths(property_name_prefix + ".permitted.paths"));
481 failure_guard.Disable();
486 NamespaceConfig* Config::create_namespace_config(const std::string& name) {
487 namespace_configs_.push_back(std::unique_ptr<NamespaceConfig>(new NamespaceConfig(name)));
488 NamespaceConfig* ns_config_ptr = namespace_configs_.back().get();
489 namespace_configs_map_[name] = ns_config_ptr;
490 return ns_config_ptr;
493 void Config::clear() {
494 namespace_configs_.clear();
495 namespace_configs_map_.clear();