summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--adb/adb_unique_fd.h9
-rw-r--r--init/property_service.cpp50
-rw-r--r--init/property_service.h5
-rw-r--r--libnativeloader/native_loader.cpp86
-rw-r--r--libnativeloader/test/Android.bp20
-rw-r--r--libnativeloader/test/Android.mk7
-rw-r--r--libnativeloader/test/public.libraries-product1.txt2
-rw-r--r--libnativeloader/test/src/android/test/app/TestActivity.java2
-rw-r--r--libunwindstack/Android.bp17
-rw-r--r--libunwindstack/LocalUnwinder.cpp146
-rw-r--r--libunwindstack/Maps.cpp79
-rw-r--r--libunwindstack/include/unwindstack/LocalUnwinder.h86
-rw-r--r--libunwindstack/include/unwindstack/Maps.h13
-rw-r--r--libunwindstack/tests/LocalUnwinderTest.cpp207
-rw-r--r--libunwindstack/tests/TestLocal.cpp39
-rw-r--r--libunwindstack/tests/UnwindTest.cpp7
-rw-r--r--rootdir/etc/ld.config.txt15
-rw-r--r--rootdir/etc/ld.config.vndk_lite.txt9
18 files changed, 739 insertions, 60 deletions
diff --git a/adb/adb_unique_fd.h b/adb/adb_unique_fd.h
index 7d2354d0e..d1dc9d10e 100644
--- a/adb/adb_unique_fd.h
+++ b/adb/adb_unique_fd.h
@@ -16,6 +16,7 @@
16 16
17#pragma once 17#pragma once
18 18
19#include <errno.h>
19#include <unistd.h> 20#include <unistd.h>
20 21
21#include <android-base/unique_fd.h> 22#include <android-base/unique_fd.h>
@@ -48,14 +49,18 @@ inline bool Pipe(unique_fd* read, unique_fd* write, int flags = 0) {
48 if (flags & O_CLOEXEC) { 49 if (flags & O_CLOEXEC) {
49 if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 || 50 if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 ||
50 fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) { 51 fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) {
51 PLOG(FATAL) << "failed to set FD_CLOEXEC on newly created pipe"; 52 close(pipefd[0]);
53 close(pipefd[1]);
54 return false;
52 } 55 }
53 } 56 }
54 57
55 if (flags & O_NONBLOCK) { 58 if (flags & O_NONBLOCK) {
56 if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0 || 59 if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0 ||
57 fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) { 60 fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) {
58 PLOG(FATAL) << "failed to set O_NONBLOCK on newly created pipe"; 61 close(pipefd[0]);
62 close(pipefd[1]);
63 return false;
59 } 64 }
60 } 65 }
61#endif 66#endif
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 741fde0b9..d1c427dba 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -95,6 +95,11 @@ uint32_t (*property_set)(const std::string& name, const std::string& value) = In
95 95
96void CreateSerializedPropertyInfo(); 96void CreateSerializedPropertyInfo();
97 97
98struct PropertyAuditData {
99 const ucred* cr;
100 const char* name;
101};
102
98void property_init() { 103void property_init() {
99 mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH); 104 mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
100 CreateSerializedPropertyInfo(); 105 CreateSerializedPropertyInfo();
@@ -111,7 +116,7 @@ static bool CheckMacPerms(const std::string& name, const char* target_context,
111 return false; 116 return false;
112 } 117 }
113 118
114 property_audit_data audit_data; 119 PropertyAuditData audit_data;
115 120
116 audit_data.name = name.c_str(); 121 audit_data.name = name.c_str();
117 audit_data.cr = &cr; 122 audit_data.cr = &cr;
@@ -393,6 +398,35 @@ class SocketConnection {
393 DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection); 398 DISALLOW_IMPLICIT_CONSTRUCTORS(SocketConnection);
394}; 399};
395 400
401bool CheckControlPropertyPerms(const std::string& name, const std::string& value,
402 const std::string& source_context, const ucred& cr) {
403 // We check the legacy method first but these properties are dontaudit, so we only log an audit
404 // if the newer method fails as well. We only do this with the legacy ctl. properties.
405 if (name == "ctl.start" || name == "ctl.stop" || name == "ctl.restart") {
406 // The legacy permissions model is that ctl. properties have their name ctl.<action> and
407 // their value is the name of the service to apply that action to. Permissions for these
408 // actions are based on the service, so we must create a fake name of ctl.<service> to
409 // check permissions.
410 auto control_string_legacy = "ctl." + value;
411 const char* target_context_legacy = nullptr;
412 const char* type_legacy = nullptr;
413 property_info_area->GetPropertyInfo(control_string_legacy.c_str(), &target_context_legacy,
414 &type_legacy);
415
416 if (CheckMacPerms(control_string_legacy, target_context_legacy, source_context.c_str(), cr)) {
417 return true;
418 }
419 }
420
421 auto control_string_full = name + "$" + value;
422 const char* target_context_full = nullptr;
423 const char* type_full = nullptr;
424 property_info_area->GetPropertyInfo(control_string_full.c_str(), &target_context_full,
425 &type_full);
426
427 return CheckMacPerms(control_string_full, target_context_full, source_context.c_str(), cr);
428}
429
396// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*. 430// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
397uint32_t HandlePropertySet(const std::string& name, const std::string& value, 431uint32_t HandlePropertySet(const std::string& name, const std::string& value,
398 const std::string& source_context, const ucred& cr, std::string* error) { 432 const std::string& source_context, const ucred& cr, std::string* error) {
@@ -402,15 +436,9 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value,
402 } 436 }
403 437
404 if (StartsWith(name, "ctl.")) { 438 if (StartsWith(name, "ctl.")) {
405 // ctl. properties have their name ctl.<action> and their value is the name of the service 439 if (!CheckControlPropertyPerms(name, value, source_context, cr)) {
406 // to apply that action to. Permissions for these actions are based on the service, so we 440 *error = StringPrintf("Invalid permissions to perform '%s' on '%s'", name.c_str() + 4,
407 // must create a fake name of ctl.<service> to check permissions. 441 value.c_str());
408 auto control_string = "ctl." + value;
409 const char* target_context = nullptr;
410 const char* type = nullptr;
411 property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
412 if (!CheckMacPerms(control_string, target_context, source_context.c_str(), cr)) {
413 *error = StringPrintf("Unable to '%s' service %s", name.c_str() + 4, value.c_str());
414 return PROP_ERROR_HANDLE_CONTROL_MESSAGE; 442 return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
415 } 443 }
416 444
@@ -742,7 +770,7 @@ void load_system_props() {
742} 770}
743 771
744static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) { 772static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
745 property_audit_data* d = reinterpret_cast<property_audit_data*>(data); 773 auto* d = reinterpret_cast<PropertyAuditData*>(data);
746 774
747 if (!d || !d->name || !d->cr) { 775 if (!d || !d->name || !d->cr) {
748 LOG(ERROR) << "AuditCallback invoked with null data arguments!"; 776 LOG(ERROR) << "AuditCallback invoked with null data arguments!";
diff --git a/init/property_service.h b/init/property_service.h
index 4a354c27f..cacd987f7 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -26,11 +26,6 @@
26namespace android { 26namespace android {
27namespace init { 27namespace init {
28 28
29struct property_audit_data {
30 const ucred* cr;
31 const char* name;
32};
33
34extern uint32_t (*property_set)(const std::string& name, const std::string& value); 29extern uint32_t (*property_set)(const std::string& name, const std::string& value);
35 30
36uint32_t HandlePropertySet(const std::string& name, const std::string& value, 31uint32_t HandlePropertySet(const std::string& name, const std::string& value,
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 0ebb22647..7fef10685 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -46,6 +46,8 @@
46 "%s:%d: %s CHECK '" #predicate "' failed.",\ 46 "%s:%d: %s CHECK '" #predicate "' failed.",\
47 __FILE__, __LINE__, __FUNCTION__) 47 __FILE__, __LINE__, __FUNCTION__)
48 48
49using namespace std::string_literals;
50
49namespace android { 51namespace android {
50 52
51#if defined(__ANDROID__) 53#if defined(__ANDROID__)
@@ -236,10 +238,15 @@ class LibraryNamespaces {
236 // Different name is useful for debugging 238 // Different name is useful for debugging
237 namespace_name = kVendorClassloaderNamespaceName; 239 namespace_name = kVendorClassloaderNamespaceName;
238 ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str()); 240 ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str());
239 } else if (!oem_public_libraries_.empty()) { 241 } else {
240 // oem_public_libraries are NOT available to vendor apks, otherwise it 242 // oem and product public libraries are NOT available to vendor apks, otherwise it
241 // would be system->vendor violation. 243 // would be system->vendor violation.
242 system_exposed_libraries = system_exposed_libraries + ":" + oem_public_libraries_.c_str(); 244 if (!oem_public_libraries_.empty()) {
245 system_exposed_libraries = system_exposed_libraries + ':' + oem_public_libraries_;
246 }
247 if (!product_public_libraries_.empty()) {
248 system_exposed_libraries = system_exposed_libraries + ':' + product_public_libraries_;
249 }
243 } 250 }
244 251
245 NativeLoaderNamespace native_loader_ns; 252 NativeLoaderNamespace native_loader_ns;
@@ -351,6 +358,8 @@ class LibraryNamespaces {
351 std::string vndksp_native_libraries_system_config = 358 std::string vndksp_native_libraries_system_config =
352 root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot; 359 root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot;
353 360
361 std::string product_public_native_libraries_dir = "/product/etc";
362
354 std::string error_msg; 363 std::string error_msg;
355 LOG_ALWAYS_FATAL_IF( 364 LOG_ALWAYS_FATAL_IF(
356 !ReadConfig(public_native_libraries_system_config, &sonames, always_true, &error_msg), 365 !ReadConfig(public_native_libraries_system_config, &sonames, always_true, &error_msg),
@@ -373,7 +382,7 @@ class LibraryNamespaces {
373 // 382 //
374 // TODO(dimitry): this is a bit misleading since we do not know 383 // TODO(dimitry): this is a bit misleading since we do not know
375 // if the vendor public library is going to be opened from /vendor/lib 384 // if the vendor public library is going to be opened from /vendor/lib
376 // we might as well end up loading them from /system/lib 385 // we might as well end up loading them from /system/lib or /product/lib
377 // For now we rely on CTS test to catch things like this but 386 // For now we rely on CTS test to catch things like this but
378 // it should probably be addressed in the future. 387 // it should probably be addressed in the future.
379 for (const auto& soname : sonames) { 388 for (const auto& soname : sonames) {
@@ -387,13 +396,43 @@ class LibraryNamespaces {
387 // system libs that are exposed to apps. The libs in the txt files must be 396 // system libs that are exposed to apps. The libs in the txt files must be
388 // named as lib<name>.<companyname>.so. 397 // named as lib<name>.<companyname>.so.
389 sonames.clear(); 398 sonames.clear();
390 std::string dirname = base::Dirname(public_native_libraries_system_config); 399 ReadExtensionLibraries(base::Dirname(public_native_libraries_system_config).c_str(), &sonames);
391 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname.c_str()), closedir); 400 oem_public_libraries_ = base::Join(sonames, ':');
401
402 // read /product/etc/public.libraries-<companyname>.txt which contain partner defined
403 // product libs that are exposed to apps.
404 sonames.clear();
405 ReadExtensionLibraries(product_public_native_libraries_dir.c_str(), &sonames);
406 product_public_libraries_ = base::Join(sonames, ':');
407
408 // Insert VNDK version to llndk and vndksp config file names.
409 insert_vndk_version_str(&llndk_native_libraries_system_config);
410 insert_vndk_version_str(&vndksp_native_libraries_system_config);
411
412 sonames.clear();
413 ReadConfig(llndk_native_libraries_system_config, &sonames, always_true);
414 system_llndk_libraries_ = base::Join(sonames, ':');
415
416 sonames.clear();
417 ReadConfig(vndksp_native_libraries_system_config, &sonames, always_true);
418 system_vndksp_libraries_ = base::Join(sonames, ':');
419
420 sonames.clear();
421 // This file is optional, quietly ignore if the file does not exist.
422 ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr);
423
424 vendor_public_libraries_ = base::Join(sonames, ':');
425 }
426
427 void Reset() { namespaces_.clear(); }
428
429 private:
430 void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
431 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
392 if (dir != nullptr) { 432 if (dir != nullptr) {
393 // Failing to opening the dir is not an error, which can happen in 433 // Failing to opening the dir is not an error, which can happen in
394 // webview_zygote. 434 // webview_zygote.
395 struct dirent* ent; 435 while (struct dirent* ent = readdir(dir.get())) {
396 while ((ent = readdir(dir.get())) != nullptr) {
397 if (ent->d_type != DT_REG && ent->d_type != DT_LNK) { 436 if (ent->d_type != DT_REG && ent->d_type != DT_LNK) {
398 continue; 437 continue;
399 } 438 }
@@ -403,14 +442,17 @@ class LibraryNamespaces {
403 const size_t start = kPublicNativeLibrariesExtensionConfigPrefixLen; 442 const size_t start = kPublicNativeLibrariesExtensionConfigPrefixLen;
404 const size_t end = filename.size() - kPublicNativeLibrariesExtensionConfigSuffixLen; 443 const size_t end = filename.size() - kPublicNativeLibrariesExtensionConfigSuffixLen;
405 const std::string company_name = filename.substr(start, end - start); 444 const std::string company_name = filename.substr(start, end - start);
406 const std::string config_file_path = dirname + "/" + filename; 445 const std::string config_file_path = dirname + "/"s + filename;
407 LOG_ALWAYS_FATAL_IF( 446 LOG_ALWAYS_FATAL_IF(
408 company_name.empty(), 447 company_name.empty(),
409 "Error extracting company name from public native library list file path \"%s\"", 448 "Error extracting company name from public native library list file path \"%s\"",
410 config_file_path.c_str()); 449 config_file_path.c_str());
450
451 std::string error_msg;
452
411 LOG_ALWAYS_FATAL_IF( 453 LOG_ALWAYS_FATAL_IF(
412 !ReadConfig( 454 !ReadConfig(
413 config_file_path, &sonames, 455 config_file_path, sonames,
414 [&company_name](const std::string& soname, std::string* error_msg) { 456 [&company_name](const std::string& soname, std::string* error_msg) {
415 if (android::base::StartsWith(soname, "lib") && 457 if (android::base::StartsWith(soname, "lib") &&
416 android::base::EndsWith(soname, "." + company_name + ".so")) { 458 android::base::EndsWith(soname, "." + company_name + ".so")) {
@@ -427,32 +469,9 @@ class LibraryNamespaces {
427 } 469 }
428 } 470 }
429 } 471 }
430 oem_public_libraries_ = base::Join(sonames, ':');
431
432 // Insert VNDK version to llndk and vndksp config file names.
433 insert_vndk_version_str(&llndk_native_libraries_system_config);
434 insert_vndk_version_str(&vndksp_native_libraries_system_config);
435
436 sonames.clear();
437 ReadConfig(llndk_native_libraries_system_config, &sonames, always_true);
438 system_llndk_libraries_ = base::Join(sonames, ':');
439
440 sonames.clear();
441 ReadConfig(vndksp_native_libraries_system_config, &sonames, always_true);
442 system_vndksp_libraries_ = base::Join(sonames, ':');
443
444 sonames.clear();
445 // This file is optional, quietly ignore if the file does not exist.
446 ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr);
447
448 vendor_public_libraries_ = base::Join(sonames, ':');
449 } 472 }
450 473
451 void Reset() {
452 namespaces_.clear();
453 }
454 474
455 private:
456 bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames, 475 bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames,
457 const std::function<bool(const std::string& /* soname */, 476 const std::function<bool(const std::string& /* soname */,
458 std::string* /* error_msg */)>& check_soname, 477 std::string* /* error_msg */)>& check_soname,
@@ -559,6 +578,7 @@ class LibraryNamespaces {
559 std::string system_public_libraries_; 578 std::string system_public_libraries_;
560 std::string vendor_public_libraries_; 579 std::string vendor_public_libraries_;
561 std::string oem_public_libraries_; 580 std::string oem_public_libraries_;
581 std::string product_public_libraries_;
562 std::string system_llndk_libraries_; 582 std::string system_llndk_libraries_;
563 std::string system_vndksp_libraries_; 583 std::string system_vndksp_libraries_;
564 584
diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp
index 5cf88b09b..d528f3031 100644
--- a/libnativeloader/test/Android.bp
+++ b/libnativeloader/test/Android.bp
@@ -49,3 +49,23 @@ cc_library {
49 "libbase", 49 "libbase",
50 ], 50 ],
51} 51}
52
53cc_library {
54 name: "libfoo.product1",
55 srcs: ["test.cpp"],
56 cflags: ["-DLIBNAME=\"libfoo.product1.so\""],
57 product_specific: true,
58 shared_libs: [
59 "libbase",
60 ],
61}
62
63cc_library {
64 name: "libbar.product1",
65 srcs: ["test.cpp"],
66 cflags: ["-DLIBNAME=\"libbar.product1.so\""],
67 product_specific: true,
68 shared_libs: [
69 "libbase",
70 ],
71}
diff --git a/libnativeloader/test/Android.mk b/libnativeloader/test/Android.mk
index e62545465..65e7b09bc 100644
--- a/libnativeloader/test/Android.mk
+++ b/libnativeloader/test/Android.mk
@@ -30,6 +30,13 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
30include $(BUILD_PREBUILT) 30include $(BUILD_PREBUILT)
31 31
32include $(CLEAR_VARS) 32include $(CLEAR_VARS)
33LOCAL_MODULE := public.libraries-product1.txt
34LOCAL_SRC_FILES:= $(LOCAL_MODULE)
35LOCAL_MODULE_CLASS := ETC
36LOCAL_MODULE_PATH := $(TARGET_OUT_PRODUCT_ETC)
37include $(BUILD_PREBUILT)
38
39include $(CLEAR_VARS)
33LOCAL_PACKAGE_NAME := oemlibrarytest-system 40LOCAL_PACKAGE_NAME := oemlibrarytest-system
34LOCAL_MODULE_TAGS := tests 41LOCAL_MODULE_TAGS := tests
35LOCAL_MANIFEST_FILE := system/AndroidManifest.xml 42LOCAL_MANIFEST_FILE := system/AndroidManifest.xml
diff --git a/libnativeloader/test/public.libraries-product1.txt b/libnativeloader/test/public.libraries-product1.txt
new file mode 100644
index 000000000..358154c62
--- /dev/null
+++ b/libnativeloader/test/public.libraries-product1.txt
@@ -0,0 +1,2 @@
1libfoo.product1.so
2libbar.product1.so
diff --git a/libnativeloader/test/src/android/test/app/TestActivity.java b/libnativeloader/test/src/android/test/app/TestActivity.java
index 214892df2..a7a455d33 100644
--- a/libnativeloader/test/src/android/test/app/TestActivity.java
+++ b/libnativeloader/test/src/android/test/app/TestActivity.java
@@ -29,6 +29,8 @@ public class TestActivity extends Activity {
29 tryLoadingLib("bar.oem1"); 29 tryLoadingLib("bar.oem1");
30 tryLoadingLib("foo.oem2"); 30 tryLoadingLib("foo.oem2");
31 tryLoadingLib("bar.oem2"); 31 tryLoadingLib("bar.oem2");
32 tryLoadingLib("foo.product1");
33 tryLoadingLib("bar.product1");
32 } 34 }
33 35
34 private void tryLoadingLib(String name) { 36 private void tryLoadingLib(String name) {
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index a6bf73073..435ed9462 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -62,6 +62,7 @@ cc_library {
62 "MapInfo.cpp", 62 "MapInfo.cpp",
63 "Maps.cpp", 63 "Maps.cpp",
64 "Memory.cpp", 64 "Memory.cpp",
65 "LocalUnwinder.cpp",
65 "Regs.cpp", 66 "Regs.cpp",
66 "RegsArm.cpp", 67 "RegsArm.cpp",
67 "RegsArm64.cpp", 68 "RegsArm64.cpp",
@@ -125,6 +126,21 @@ cc_library {
125//------------------------------------------------------------------------- 126//-------------------------------------------------------------------------
126// Unit Tests 127// Unit Tests
127//------------------------------------------------------------------------- 128//-------------------------------------------------------------------------
129cc_test_library {
130 name: "libunwindstack_local",
131 defaults: ["libunwindstack_flags"],
132 srcs: ["tests/TestLocal.cpp"],
133
134 cflags: [
135 "-O0",
136 "-g",
137 ],
138
139 shared_libs: [
140 "libunwindstack",
141 ],
142}
143
128cc_test { 144cc_test {
129 name: "libunwindstack_test", 145 name: "libunwindstack_test",
130 defaults: ["libunwindstack_flags"], 146 defaults: ["libunwindstack_flags"],
@@ -151,6 +167,7 @@ cc_test {
151 "tests/ElfTest.cpp", 167 "tests/ElfTest.cpp",
152 "tests/ElfTestUtils.cpp", 168 "tests/ElfTestUtils.cpp",
153 "tests/JitDebugTest.cpp", 169 "tests/JitDebugTest.cpp",
170 "tests/LocalUnwinderTest.cpp",
154 "tests/LogFake.cpp", 171 "tests/LogFake.cpp",
155 "tests/MapInfoGetElfTest.cpp", 172 "tests/MapInfoGetElfTest.cpp",
156 "tests/MapInfoGetLoadBiasTest.cpp", 173 "tests/MapInfoGetLoadBiasTest.cpp",
diff --git a/libunwindstack/LocalUnwinder.cpp b/libunwindstack/LocalUnwinder.cpp
new file mode 100644
index 000000000..952b332f0
--- /dev/null
+++ b/libunwindstack/LocalUnwinder.cpp
@@ -0,0 +1,146 @@
1/*
2 * Copyright (C) 2018 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 <pthread.h>
30#include <stdint.h>
31
32#include <memory>
33#include <string>
34#include <vector>
35
36#include <unwindstack/Elf.h>
37#include <unwindstack/LocalUnwinder.h>
38#include <unwindstack/MapInfo.h>
39#include <unwindstack/Maps.h>
40#include <unwindstack/Memory.h>
41#include <unwindstack/Regs.h>
42#include <unwindstack/RegsGetLocal.h>
43
44namespace unwindstack {
45
46bool LocalUnwinder::Init() {
47 pthread_rwlock_init(&maps_rwlock_, nullptr);
48
49 // Create the maps.
50 maps_.reset(new unwindstack::LocalUpdatableMaps());
51 if (!maps_->Parse()) {
52 maps_.reset();
53 return false;
54 }
55
56 process_memory_ = unwindstack::Memory::CreateProcessMemory(getpid());
57
58 return true;
59}
60
61bool LocalUnwinder::ShouldSkipLibrary(const std::string& map_name) {
62 for (const std::string& skip_library : skip_libraries_) {
63 if (skip_library == map_name) {
64 return true;
65 }
66 }
67 return false;
68}
69
70MapInfo* LocalUnwinder::GetMapInfo(uint64_t pc) {
71 pthread_rwlock_rdlock(&maps_rwlock_);
72 MapInfo* map_info = maps_->Find(pc);
73 pthread_rwlock_unlock(&maps_rwlock_);
74
75 if (map_info == nullptr) {
76 pthread_rwlock_wrlock(&maps_rwlock_);
77 // This is guaranteed not to invalidate any previous MapInfo objects so
78 // we don't need to worry about any MapInfo* values already in use.
79 if (maps_->Reparse()) {
80 map_info = maps_->Find(pc);
81 }
82 pthread_rwlock_unlock(&maps_rwlock_);
83 }
84
85 return map_info;
86}
87
88bool LocalUnwinder::Unwind(std::vector<LocalFrameData>* frame_info, size_t max_frames) {
89 std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
90 unwindstack::RegsGetLocal(regs.get());
91
92 size_t num_frames = 0;
93 bool adjust_pc = false;
94 while (true) {
95 uint64_t cur_pc = regs->pc();
96 uint64_t cur_sp = regs->sp();
97
98 MapInfo* map_info = GetMapInfo(cur_pc);
99 if (map_info == nullptr) {
100 break;
101 }
102
103 Elf* elf = map_info->GetElf(process_memory_, true);
104 uint64_t rel_pc = elf->GetRelPc(cur_pc, map_info);
105 uint64_t step_pc = rel_pc;
106 uint64_t pc_adjustment;
107 if (adjust_pc) {
108 pc_adjustment = regs->GetPcAdjustment(rel_pc, elf);
109 } else {
110 pc_adjustment = 0;
111 }
112 step_pc -= pc_adjustment;
113 // Skip any locations that are within this library.
114 if (num_frames != 0 || !ShouldSkipLibrary(map_info->name)) {
115 // Add frame information.
116 std::string func_name;
117 uint64_t func_offset;
118 if (elf->GetFunctionName(rel_pc, &func_name, &func_offset)) {
119 frame_info->emplace_back(map_info, cur_pc - pc_adjustment, rel_pc - pc_adjustment,
120 func_name, func_offset);
121 } else {
122 frame_info->emplace_back(map_info, cur_pc - pc_adjustment, rel_pc - pc_adjustment, "", 0);
123 }
124 num_frames++;
125 }
126 if (!elf->valid()) {
127 break;
128 }
129 if (frame_info->size() == max_frames) {
130 break;
131 }
132
133 adjust_pc = true;
134 bool finished;
135 if (!elf->Step(rel_pc, step_pc, regs.get(), process_memory_.get(), &finished) || finished) {
136 break;
137 }
138 // pc and sp are the same, terminate the unwind.
139 if (cur_pc == regs->pc() && cur_sp == regs->sp()) {
140 break;
141 }
142 }
143 return num_frames != 0;
144}
145
146} // namespace unwindstack
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index bb682ea69..e676a5a97 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -105,4 +105,83 @@ const std::string RemoteMaps::GetMapsFile() const {
105 return "/proc/" + std::to_string(pid_) + "/maps"; 105 return "/proc/" + std::to_string(pid_) + "/maps";
106} 106}
107 107
108const std::string LocalUpdatableMaps::GetMapsFile() const {
109 return "/proc/self/maps";
110}
111
112bool LocalUpdatableMaps::Reparse() {
113 // New maps will be added at the end without deleting the old ones.
114 size_t last_map_idx = maps_.size();
115 if (!Parse()) {
116 // Delete any maps added by the Parse call.
117 for (size_t i = last_map_idx; i < maps_.size(); i++) {
118 delete maps_[i];
119 }
120 maps_.resize(last_map_idx);
121 return false;
122 }
123
124 size_t total_entries = maps_.size();
125 size_t search_map_idx = 0;
126 for (size_t new_map_idx = last_map_idx; new_map_idx < maps_.size(); new_map_idx++) {
127 MapInfo* new_map_info = maps_[new_map_idx];
128 uint64_t start = new_map_info->start;
129 uint64_t end = new_map_info->end;
130 uint64_t flags = new_map_info->flags;
131 std::string* name = &new_map_info->name;
132 for (size_t old_map_idx = search_map_idx; old_map_idx < last_map_idx; old_map_idx++) {
133 MapInfo* info = maps_[old_map_idx];
134 if (start == info->start && end == info->end && flags == info->flags && *name == info->name) {
135 // No need to check
136 search_map_idx = old_map_idx + 1;
137 delete new_map_info;
138 maps_[new_map_idx] = nullptr;
139 total_entries--;
140 break;
141 } else if (info->start > start) {
142 // Stop, there isn't going to be a match.
143 search_map_idx = old_map_idx;
144 break;
145 }
146
147 // Never delete these maps, they may be in use. The assumption is
148 // that there will only every be a handfull of these so waiting
149 // to destroy them is not too expensive.
150 saved_maps_.push_back(info);
151 maps_[old_map_idx] = nullptr;
152 total_entries--;
153 }
154 if (search_map_idx >= last_map_idx) {
155 break;
156 }
157 }
158
159 // Now move out any of the maps that never were found.
160 for (size_t i = search_map_idx; i < last_map_idx; i++) {
161 saved_maps_.push_back(maps_[i]);
162 maps_[i] = nullptr;
163 total_entries--;
164 }
165
166 // Sort all of the values such that the nullptrs wind up at the end, then
167 // resize them away.
168 std::sort(maps_.begin(), maps_.end(), [](const auto* a, const auto* b) {
169 if (a == nullptr) {
170 return false;
171 } else if (b == nullptr) {
172 return true;
173 }
174 return a->start < b->start;
175 });
176 maps_.resize(total_entries);
177
178 return true;
179}
180
181LocalUpdatableMaps::~LocalUpdatableMaps() {
182 for (auto map_info : saved_maps_) {
183 delete map_info;
184 }
185}
186
108} // namespace unwindstack 187} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/LocalUnwinder.h b/libunwindstack/include/unwindstack/LocalUnwinder.h
new file mode 100644
index 000000000..80bb53ec1
--- /dev/null
+++ b/libunwindstack/include/unwindstack/LocalUnwinder.h
@@ -0,0 +1,86 @@
1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _LIBUNWINDSTACK_LOCAL_UNWINDER_H
18#define _LIBUNWINDSTACK_LOCAL_UNWINDER_H
19
20#include <pthread.h>
21#include <stdint.h>
22#include <sys/types.h>
23
24#include <memory>
25#include <string>
26#include <vector>
27
28#include <unwindstack/Error.h>
29#include <unwindstack/Maps.h>
30#include <unwindstack/Memory.h>
31
32namespace unwindstack {
33
34// Forward declarations.
35class Elf;
36struct MapInfo;
37
38struct LocalFrameData {
39 LocalFrameData(MapInfo* map_info, uint64_t pc, uint64_t rel_pc, const std::string& function_name,
40 uint64_t function_offset)
41 : map_info(map_info),
42 pc(pc),
43 rel_pc(rel_pc),
44 function_name(function_name),
45 function_offset(function_offset) {}
46
47 MapInfo* map_info;
48 uint64_t pc;
49 uint64_t rel_pc;
50 std::string function_name;
51 uint64_t function_offset;
52};
53
54// This is a specialized class that should only be used for doing local unwinds.
55// The Unwind call can be made as multiple times on the same object, and it can
56// be called by multiple threads at the same time.
57// It is designed to be used in debugging circumstances to get a stack trace
58// as fast as possible.
59class LocalUnwinder {
60 public:
61 LocalUnwinder() = default;
62 LocalUnwinder(const std::vector<std::string>& skip_libraries) : skip_libraries_(skip_libraries) {}
63 ~LocalUnwinder() = default;
64
65 bool Init();
66
67 bool Unwind(std::vector<LocalFrameData>* frame_info, size_t max_frames);
68
69 bool ShouldSkipLibrary(const std::string& map_name);
70
71 MapInfo* GetMapInfo(uint64_t pc);
72
73 ErrorCode LastErrorCode() { return last_error_.code; }
74 uint64_t LastErrorAddress() { return last_error_.address; }
75
76 private:
77 pthread_rwlock_t maps_rwlock_;
78 std::unique_ptr<LocalUpdatableMaps> maps_ = nullptr;
79 std::shared_ptr<Memory> process_memory_;
80 std::vector<std::string> skip_libraries_;
81 ErrorData last_error_;
82};
83
84} // namespace unwindstack
85
86#endif // _LIBUNWINDSTACK_LOCAL_UNWINDER_H
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
index 74e5c4729..67fbed21a 100644
--- a/libunwindstack/include/unwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -87,6 +87,19 @@ class LocalMaps : public RemoteMaps {
87 virtual ~LocalMaps() = default; 87 virtual ~LocalMaps() = default;
88}; 88};
89 89
90class LocalUpdatableMaps : public Maps {
91 public:
92 LocalUpdatableMaps() : Maps() {}
93 virtual ~LocalUpdatableMaps();
94
95 bool Reparse();
96
97 const std::string GetMapsFile() const override;
98
99 private:
100 std::vector<MapInfo*> saved_maps_;
101};
102
90class BufferMaps : public Maps { 103class BufferMaps : public Maps {
91 public: 104 public:
92 BufferMaps(const char* buffer) : buffer_(buffer) {} 105 BufferMaps(const char* buffer) : buffer_(buffer) {}
diff --git a/libunwindstack/tests/LocalUnwinderTest.cpp b/libunwindstack/tests/LocalUnwinderTest.cpp
new file mode 100644
index 000000000..56a18cde2
--- /dev/null
+++ b/libunwindstack/tests/LocalUnwinderTest.cpp
@@ -0,0 +1,207 @@
1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <dlfcn.h>
18#include <inttypes.h>
19#include <signal.h>
20#include <stdint.h>
21
22#include <memory>
23#include <string>
24#include <vector>
25
26#include <gtest/gtest.h>
27
28#include <android-base/stringprintf.h>
29
30#include <unwindstack/LocalUnwinder.h>
31
32namespace unwindstack {
33
34static std::vector<LocalFrameData>* g_frame_info;
35static LocalUnwinder* g_unwinder;
36
37extern "C" void SignalLocalInnerFunction() {
38 g_unwinder->Unwind(g_frame_info, 256);
39}
40
41extern "C" void SignalLocalMiddleFunction() {
42 SignalLocalInnerFunction();
43}
44
45extern "C" void SignalLocalOuterFunction() {
46 SignalLocalMiddleFunction();
47}
48
49static void SignalLocalCallerHandler(int, siginfo_t*, void*) {
50 SignalLocalOuterFunction();
51}
52
53static std::string ErrorMsg(const std::vector<const char*>& function_names,
54 const std::vector<LocalFrameData>& frame_info) {
55 std::string unwind;
56 size_t i = 0;
57 for (const auto& frame : frame_info) {
58 unwind += android::base::StringPrintf("#%02zu pc 0x%" PRIx64 " rel_pc 0x%" PRIx64, i++,
59 frame.pc, frame.rel_pc);
60 if (frame.map_info != nullptr) {
61 if (!frame.map_info->name.empty()) {
62 unwind += " " + frame.map_info->name;
63 } else {
64 unwind += android::base::StringPrintf(" 0x%" PRIx64 "-0x%" PRIx64, frame.map_info->start,
65 frame.map_info->end);
66 }
67 if (frame.map_info->offset != 0) {
68 unwind += android::base::StringPrintf(" offset 0x%" PRIx64, frame.map_info->offset);
69 }
70 }
71 if (!frame.function_name.empty()) {
72 unwind += " " + frame.function_name;
73 if (frame.function_offset != 0) {
74 unwind += android::base::StringPrintf("+%" PRId64, frame.function_offset);
75 }
76 }
77 unwind += '\n';
78 }
79
80 return std::string(
81 "Unwind completed without finding all frames\n"
82 " Looking for function: ") +
83 function_names.front() + "\n" + "Unwind data:\n" + unwind;
84}
85
86// This test assumes that this code is compiled with optimizations turned
87// off. If this doesn't happen, then all of the calls will be optimized
88// away.
89extern "C" void LocalInnerFunction(LocalUnwinder* unwinder, bool unwind_through_signal) {
90 std::vector<LocalFrameData> frame_info;
91 g_frame_info = &frame_info;
92 g_unwinder = unwinder;
93 std::vector<const char*> expected_function_names;
94
95 if (unwind_through_signal) {
96 struct sigaction act, oldact;
97 memset(&act, 0, sizeof(act));
98 act.sa_sigaction = SignalLocalCallerHandler;
99 act.sa_flags = SA_RESTART | SA_ONSTACK;
100 ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
101
102 raise(SIGUSR1);
103
104 ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
105
106 expected_function_names = {"LocalOuterFunction", "LocalMiddleFunction",
107 "LocalInnerFunction", "SignalLocalOuterFunction",
108 "SignalLocalMiddleFunction", "SignalLocalInnerFunction"};
109 } else {
110 ASSERT_TRUE(unwinder->Unwind(&frame_info, 256));
111
112 expected_function_names = {"LocalOuterFunction", "LocalMiddleFunction", "LocalInnerFunction"};
113 }
114
115 for (auto& frame : frame_info) {
116 if (frame.function_name == expected_function_names.back()) {
117 expected_function_names.pop_back();
118 if (expected_function_names.empty()) {
119 break;
120 }
121 }
122 }
123
124 ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, frame_info);
125}
126
127extern "C" void LocalMiddleFunction(LocalUnwinder* unwinder, bool unwind_through_signal) {
128 LocalInnerFunction(unwinder, unwind_through_signal);
129}
130
131extern "C" void LocalOuterFunction(LocalUnwinder* unwinder, bool unwind_through_signal) {
132 LocalMiddleFunction(unwinder, unwind_through_signal);
133}
134
135class LocalUnwinderTest : public ::testing::Test {
136 protected:
137 void SetUp() override {
138 unwinder_.reset(new LocalUnwinder);
139 ASSERT_TRUE(unwinder_->Init());
140 }
141
142 std::unique_ptr<LocalUnwinder> unwinder_;
143};
144
145TEST_F(LocalUnwinderTest, local) {
146 LocalOuterFunction(unwinder_.get(), false);
147}
148
149TEST_F(LocalUnwinderTest, local_signal) {
150 LocalOuterFunction(unwinder_.get(), true);
151}
152
153TEST_F(LocalUnwinderTest, local_multiple) {
154 ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false));
155
156 ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), true));
157
158 ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false));
159
160 ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), true));
161}
162
163// This test verifies that doing an unwind before and after a dlopen
164// works. It's verifying that the maps read during the first unwind
165// do not cause a problem when doing the unwind using the code in
166// the dlopen'd code.
167TEST_F(LocalUnwinderTest, unwind_after_dlopen) {
168 // Prime the maps data.
169 ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false));
170
171 std::string testlib(testing::internal::GetArgvs()[0]);
172 auto const value = testlib.find_last_of('/');
173 if (value == std::string::npos) {
174 testlib = "../";
175 } else {
176 testlib = testlib.substr(0, value + 1) + "../";
177 }
178 testlib += "libunwindstack_local.so";
179
180 void* handle = dlopen(testlib.c_str(), RTLD_NOW);
181 ASSERT_TRUE(handle != nullptr);
182
183 void (*unwind_function)(void*, void*) =
184 reinterpret_cast<void (*)(void*, void*)>(dlsym(handle, "TestlibLevel1"));
185 ASSERT_TRUE(unwind_function != nullptr);
186
187 std::vector<LocalFrameData> frame_info;
188 unwind_function(unwinder_.get(), &frame_info);
189
190 ASSERT_EQ(0, dlclose(handle));
191
192 std::vector<const char*> expected_function_names{"TestlibLevel1", "TestlibLevel2",
193 "TestlibLevel3", "TestlibLevel4"};
194
195 for (auto& frame : frame_info) {
196 if (frame.function_name == expected_function_names.back()) {
197 expected_function_names.pop_back();
198 if (expected_function_names.empty()) {
199 break;
200 }
201 }
202 }
203
204 ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, frame_info);
205}
206
207} // namespace unwindstack
diff --git a/libunwindstack/tests/TestLocal.cpp b/libunwindstack/tests/TestLocal.cpp
new file mode 100644
index 000000000..fa0baff36
--- /dev/null
+++ b/libunwindstack/tests/TestLocal.cpp
@@ -0,0 +1,39 @@
1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <unwindstack/LocalUnwinder.h>
18
19#include <vector>
20
21extern "C" void TestlibLevel4(void* unwinder_data, void* frame_data) {
22 unwindstack::LocalUnwinder* unwinder =
23 reinterpret_cast<unwindstack::LocalUnwinder*>(unwinder_data);
24 std::vector<unwindstack::LocalFrameData>* frame_info =
25 reinterpret_cast<std::vector<unwindstack::LocalFrameData>*>(frame_data);
26 unwinder->Unwind(frame_info, 256);
27}
28
29extern "C" void TestlibLevel3(void* unwinder_data, void* frame_data) {
30 TestlibLevel4(unwinder_data, frame_data);
31}
32
33extern "C" void TestlibLevel2(void* unwinder_data, void* frame_data) {
34 TestlibLevel3(unwinder_data, frame_data);
35}
36
37extern "C" void TestlibLevel1(void* unwinder_data, void* frame_data) {
38 TestlibLevel2(unwinder_data, frame_data);
39}
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 242cc6a6f..83695bbcd 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -106,15 +106,12 @@ static void VerifyUnwind(pid_t pid, Maps* maps, Regs* regs,
106 Unwinder unwinder(512, maps, regs, process_memory); 106 Unwinder unwinder(512, maps, regs, process_memory);
107 unwinder.Unwind(); 107 unwinder.Unwind();
108 108
109 std::string expected_function = expected_function_names.back();
110 expected_function_names.pop_back();
111 for (auto& frame : unwinder.frames()) { 109 for (auto& frame : unwinder.frames()) {
112 if (frame.function_name == expected_function) { 110 if (frame.function_name == expected_function_names.back()) {
111 expected_function_names.pop_back();
113 if (expected_function_names.empty()) { 112 if (expected_function_names.empty()) {
114 break; 113 break;
115 } 114 }
116 expected_function = expected_function_names.back();
117 expected_function_names.pop_back();
118 } 115 }
119 } 116 }
120 117
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index ba96cc84a..51e3f9efc 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -37,7 +37,8 @@ additional.namespaces = sphal,vndk,rs
37############################################################################### 37###############################################################################
38namespace.default.isolated = true 38namespace.default.isolated = true
39 39
40namespace.default.search.paths = /system/${LIB} 40namespace.default.search.paths = /system/${LIB}
41namespace.default.search.paths += /product/${LIB}
41 42
42# We can't have entire /system/${LIB} as permitted paths because doing so 43# We can't have entire /system/${LIB} as permitted paths because doing so
43# makes it possible to load libs in /system/${LIB}/vndk* directories by 44# makes it possible to load libs in /system/${LIB}/vndk* directories by
@@ -49,6 +50,7 @@ namespace.default.search.paths = /system/${LIB}
49namespace.default.permitted.paths = /system/${LIB}/drm 50namespace.default.permitted.paths = /system/${LIB}/drm
50namespace.default.permitted.paths += /system/${LIB}/extractors 51namespace.default.permitted.paths += /system/${LIB}/extractors
51namespace.default.permitted.paths += /system/${LIB}/hw 52namespace.default.permitted.paths += /system/${LIB}/hw
53namespace.default.permitted.paths += /product/${LIB}
52# These are where odex files are located. libart has to be able to dlopen the files 54# These are where odex files are located. libart has to be able to dlopen the files
53namespace.default.permitted.paths += /system/framework 55namespace.default.permitted.paths += /system/framework
54namespace.default.permitted.paths += /system/app 56namespace.default.permitted.paths += /system/app
@@ -68,6 +70,8 @@ namespace.default.permitted.paths += /mnt/expand
68 70
69namespace.default.asan.search.paths = /data/asan/system/${LIB} 71namespace.default.asan.search.paths = /data/asan/system/${LIB}
70namespace.default.asan.search.paths += /system/${LIB} 72namespace.default.asan.search.paths += /system/${LIB}
73namespace.default.asan.search.paths += /data/asan/product/${LIB}
74namespace.default.asan.search.paths += /product/${LIB}
71 75
72namespace.default.asan.permitted.paths = /data 76namespace.default.asan.permitted.paths = /data
73namespace.default.asan.permitted.paths += /system/${LIB}/drm 77namespace.default.asan.permitted.paths += /system/${LIB}/drm
@@ -83,6 +87,7 @@ namespace.default.asan.permitted.paths += /odm/framework
83namespace.default.asan.permitted.paths += /odm/app 87namespace.default.asan.permitted.paths += /odm/app
84namespace.default.asan.permitted.paths += /odm/priv-app 88namespace.default.asan.permitted.paths += /odm/priv-app
85namespace.default.asan.permitted.paths += /oem/app 89namespace.default.asan.permitted.paths += /oem/app
90namespace.default.asan.permitted.paths += /product/${LIB}
86namespace.default.asan.permitted.paths += /product/framework 91namespace.default.asan.permitted.paths += /product/framework
87namespace.default.asan.permitted.paths += /product/app 92namespace.default.asan.permitted.paths += /product/app
88namespace.default.asan.permitted.paths += /product/priv-app 93namespace.default.asan.permitted.paths += /product/priv-app
@@ -320,10 +325,13 @@ namespace.vndk.link.default.allow_all_shared_libs = true
320############################################################################### 325###############################################################################
321namespace.system.isolated = false 326namespace.system.isolated = false
322 327
323namespace.system.search.paths = /system/${LIB} 328namespace.system.search.paths = /system/${LIB}
329namespace.system.search.paths += /product/${LIB}
324 330
325namespace.system.asan.search.paths = /data/asan/system/${LIB} 331namespace.system.asan.search.paths = /data/asan/system/${LIB}
326namespace.system.asan.search.paths += /system/${LIB} 332namespace.system.asan.search.paths += /system/${LIB}
333namespace.system.asan.search.paths += /data/asan/product/${LIB}
334namespace.system.asan.search.paths += /product/${LIB}
327 335
328############################################################################### 336###############################################################################
329# Namespace config for binaries under /postinstall. 337# Namespace config for binaries under /postinstall.
@@ -335,4 +343,5 @@ namespace.system.asan.search.paths += /system/${LIB}
335############################################################################### 343###############################################################################
336[postinstall] 344[postinstall]
337namespace.default.isolated = false 345namespace.default.isolated = false
338namespace.default.search.paths = /system/${LIB} 346namespace.default.search.paths = /system/${LIB}
347namespace.default.search.paths += /product/${LIB}
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 1fd419586..ab0375539 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -40,6 +40,7 @@ namespace.default.isolated = false
40namespace.default.search.paths = /system/${LIB} 40namespace.default.search.paths = /system/${LIB}
41namespace.default.search.paths += /odm/${LIB} 41namespace.default.search.paths += /odm/${LIB}
42namespace.default.search.paths += /vendor/${LIB} 42namespace.default.search.paths += /vendor/${LIB}
43namespace.default.search.paths += /product/${LIB}
43 44
44namespace.default.asan.search.paths = /data/asan/system/${LIB} 45namespace.default.asan.search.paths = /data/asan/system/${LIB}
45namespace.default.asan.search.paths += /system/${LIB} 46namespace.default.asan.search.paths += /system/${LIB}
@@ -47,6 +48,8 @@ namespace.default.asan.search.paths += /data/asan/odm/${LIB}
47namespace.default.asan.search.paths += /odm/${LIB} 48namespace.default.asan.search.paths += /odm/${LIB}
48namespace.default.asan.search.paths += /data/asan/vendor/${LIB} 49namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
49namespace.default.asan.search.paths += /vendor/${LIB} 50namespace.default.asan.search.paths += /vendor/${LIB}
51namespace.default.asan.search.paths += /data/asan/product/${LIB}
52namespace.default.asan.search.paths += /product/${LIB}
50 53
51############################################################################### 54###############################################################################
52# "sphal" namespace 55# "sphal" namespace
@@ -205,6 +208,7 @@ namespace.default.search.paths += /vendor/${LIB}/vndk-sp
205namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER% 208namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
206namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER% 209namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
207namespace.default.search.paths += /system/${LIB} 210namespace.default.search.paths += /system/${LIB}
211namespace.default.search.paths += /product/${LIB}
208 212
209namespace.default.asan.search.paths = /data/asan/odm/${LIB} 213namespace.default.asan.search.paths = /data/asan/odm/${LIB}
210namespace.default.asan.search.paths += /odm/${LIB} 214namespace.default.asan.search.paths += /odm/${LIB}
@@ -224,6 +228,8 @@ namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER
224namespace.default.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER% 228namespace.default.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
225namespace.default.asan.search.paths += /data/asan/system/${LIB} 229namespace.default.asan.search.paths += /data/asan/system/${LIB}
226namespace.default.asan.search.paths += /system/${LIB} 230namespace.default.asan.search.paths += /system/${LIB}
231namespace.default.asan.search.paths += /data/asan/product/${LIB}
232namespace.default.asan.search.paths += /product/${LIB}
227 233
228############################################################################### 234###############################################################################
229# Namespace config for binaries under /postinstall. 235# Namespace config for binaries under /postinstall.
@@ -235,4 +241,5 @@ namespace.default.asan.search.paths += /system/${LIB}
235############################################################################### 241###############################################################################
236[postinstall] 242[postinstall]
237namespace.default.isolated = false 243namespace.default.isolated = false
238namespace.default.search.paths = /system/${LIB} 244namespace.default.search.paths = /system/${LIB}
245namespace.default.search.paths += /product/${LIB}