diff options
35 files changed, 662 insertions, 269 deletions
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 2529516da..0c5543ed9 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -240,11 +240,16 @@ cc_library_static { "libdebuggerd/backtrace.cpp", "libdebuggerd/gwp_asan.cpp", "libdebuggerd/open_files_list.cpp", + "libdebuggerd/scudo.cpp", "libdebuggerd/tombstone.cpp", "libdebuggerd/tombstone_proto.cpp", "libdebuggerd/utility.cpp", ], + cflags: [ + "-DUSE_SCUDO", + ], + local_include_dirs: ["libdebuggerd/include"], export_include_dirs: ["libdebuggerd/include"], @@ -256,6 +261,7 @@ cc_library_static { "bionic_libc_platform_headers", "gwp_asan_headers", "liblog_headers", + "scudo_headers", ], static_libs: [ @@ -273,6 +279,7 @@ cc_library_static { "libtombstone_proto", "libprocinfo", "libprotobuf-cpp-lite", + "libscudo", ], target: { @@ -312,11 +319,9 @@ cc_library_static { cflags: ["-DROOT_POSSIBLE"], }, - malloc_not_svelte: { - cflags: ["-DUSE_SCUDO"], - whole_static_libs: ["libscudo"], - srcs: ["libdebuggerd/scudo.cpp"], - header_libs: ["scudo_headers"], + malloc_low_memory: { + cflags: ["-UUSE_SCUDO"], + exclude_static_libs: ["libscudo"], }, }, apex_available: [ @@ -447,6 +452,7 @@ cc_binary { header_libs: [ "bionic_libc_platform_headers", + "libnative_bridge_support_accessor_headers", ], static_libs: [ @@ -456,6 +462,8 @@ cc_binary { "libtombstone_proto", "libprotobuf-cpp-lite", + + "libnative_bridge_guest_state_accessor", ], shared_libs: [ @@ -471,6 +479,15 @@ cc_binary { // Required for tests. required: ["crash_dump.policy"], + + target: { + android: { + header_libs: [ + "libnative_bridge_support_accessor_headers", // For dlext_namespaces.h + ], + shared_libs: ["libdl_android"], // For android_get_exported_namespace implementation + }, + }, } cc_binary { diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 203b4855b..77d4a07af 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -25,6 +25,7 @@ #include <sys/wait.h> #include <unistd.h> +#include <cstdint> #include <limits> #include <map> #include <memory> @@ -42,6 +43,7 @@ #include <android-base/unique_fd.h> #include <bionic/macros.h> #include <bionic/reserved_signals.h> +#include <bionic/tls_defines.h> #include <cutils/sockets.h> #include <log/log.h> #include <private/android_filesystem_config.h> @@ -52,7 +54,18 @@ #include <unwindstack/AndroidUnwinder.h> #include <unwindstack/Error.h> +#include <unwindstack/MachineArm.h> +#include <unwindstack/MachineArm64.h> +#include <unwindstack/MachineRiscv64.h> #include <unwindstack/Regs.h> +#include <unwindstack/RegsArm.h> +#include <unwindstack/RegsArm64.h> +#include <unwindstack/RegsRiscv64.h> +#include <unwindstack/UserArm.h> +#include <unwindstack/UserArm64.h> +#include <unwindstack/UserRiscv64.h> + +#include <native_bridge_support/guest_state_accessor/accessor.h> #include "libdebuggerd/backtrace.h" #include "libdebuggerd/tombstone.h" @@ -68,6 +81,10 @@ using android::base::ErrnoRestorer; using android::base::StringPrintf; using android::base::unique_fd; +// This stores guest architecture. When the architecture is supported, tombstone file will output +// guest state information. +static Architecture g_guest_arch; + static bool pid_contains_tid(int pid_proc_fd, pid_t tid) { struct stat st; std::string task_path = StringPrintf("task/%d", tid); @@ -286,28 +303,27 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, *recoverable_crash = false; if (rc == -1) { PLOG(FATAL) << "failed to read target ucontext"; - } else { - ssize_t expected_size = 0; - switch (crash_info->header.version) { - case 1: - case 2: - case 3: - expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataStatic); - break; - - case 4: - expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataDynamic); - break; - - default: - LOG(FATAL) << "unexpected CrashInfo version: " << crash_info->header.version; - break; - }; - - if (rc < expected_size) { - LOG(FATAL) << "read " << rc << " bytes when reading target crash information, expected " - << expected_size; - } + } + ssize_t expected_size = 0; + switch (crash_info->header.version) { + case 1: + case 2: + case 3: + expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataStatic); + break; + + case 4: + expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataDynamic); + break; + + default: + LOG(FATAL) << "unexpected CrashInfo version: " << crash_info->header.version; + break; + } + + if (rc < expected_size) { + LOG(FATAL) << "read " << rc << " bytes when reading target crash information, expected " + << expected_size; } switch (crash_info->header.version) { @@ -403,6 +419,107 @@ static void InstallSigPipeHandler() { sigaction(SIGPIPE, &action, nullptr); } +static bool PtracePeek(int request, pid_t tid, uintptr_t addr, void* data, std::string_view err_msg, + uintptr_t* result) { + errno = 0; + *result = ptrace(request, tid, addr, data); + if (errno != 0) { + PLOG(ERROR) << err_msg; + return false; + } + return true; +} + +static bool GetGuestRegistersFromCrashedProcess([[maybe_unused]] pid_t tid, + NativeBridgeGuestRegs* guest_regs) { + auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(tid); + + uintptr_t header_ptr = 0; + uintptr_t base = 0; +#if defined(__x86_64__) + if (!PtracePeek(PTRACE_PEEKUSER, tid, offsetof(user_regs_struct, fs_base), nullptr, + "failed to read thread register for thread " + std::to_string(tid), &base)) { + return false; + } +#elif defined(__aarch64__) + // base is implicitly casted to uint64_t. + struct iovec pt_iov { + .iov_base = &base, .iov_len = sizeof(base), + }; + + if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TLS, &pt_iov) != 0) { + PLOG(ERROR) << "failed to read thread register for thread " << tid; + } +#else + // TODO(b/339287219): Add case for Riscv host. + return false; +#endif + auto ptr_to_guest_slot = base + TLS_SLOT_NATIVE_BRIDGE_GUEST_STATE * sizeof(uintptr_t); + if (!process_memory->ReadFully(ptr_to_guest_slot, &header_ptr, sizeof(uintptr_t))) { + PLOG(ERROR) << "failed to get guest state TLS slot content for thread " << tid; + return false; + } + + NativeBridgeGuestStateHeader header; + if (!process_memory->ReadFully(header_ptr, &header, sizeof(NativeBridgeGuestStateHeader))) { + PLOG(ERROR) << "failed to get the guest state header for thread " << tid; + return false; + } + if (header.signature != NATIVE_BRIDGE_GUEST_STATE_SIGNATURE) { + // Return when ptr points to unmapped memory or no valid guest state. + return false; + } + auto guest_state_data_copy = std::make_unique<unsigned char[]>(header.guest_state_data_size); + if (!process_memory->ReadFully(reinterpret_cast<uintptr_t>(header.guest_state_data), + guest_state_data_copy.get(), header.guest_state_data_size)) { + PLOG(ERROR) << "failed to read the guest state data for thread " << tid; + return false; + } + + LoadGuestStateRegisters(guest_state_data_copy.get(), header.guest_state_data_size, guest_regs); + return true; +} + +static void ReadGuestRegisters([[maybe_unused]] std::unique_ptr<unwindstack::Regs>* regs, + pid_t tid) { + // TODO: remove [[maybe_unused]], when the ARM32 case is removed from the native bridge support. + NativeBridgeGuestRegs guest_regs; + if (!GetGuestRegistersFromCrashedProcess(tid, &guest_regs)) { + return; + } + + switch (guest_regs.guest_arch) { +#if defined(__LP64__) + case NATIVE_BRIDGE_ARCH_ARM64: { + unwindstack::arm64_user_regs arm64_user_regs = {}; + for (size_t i = 0; i < unwindstack::ARM64_REG_R31; i++) { + arm64_user_regs.regs[i] = guest_regs.regs_arm64.x[i]; + } + arm64_user_regs.sp = guest_regs.regs_arm64.sp; + arm64_user_regs.pc = guest_regs.regs_arm64.ip; + regs->reset(unwindstack::RegsArm64::Read(&arm64_user_regs)); + + g_guest_arch = Architecture::ARM64; + break; + } + case NATIVE_BRIDGE_ARCH_RISCV64: { + unwindstack::riscv64_user_regs riscv64_user_regs = {}; + // RISCV64_REG_PC is at the first position. + riscv64_user_regs.regs[0] = guest_regs.regs_riscv64.ip; + for (size_t i = 1; i < unwindstack::RISCV64_REG_REAL_COUNT; i++) { + riscv64_user_regs.regs[i] = guest_regs.regs_riscv64.x[i]; + } + regs->reset(unwindstack::RegsRiscv64::Read(&riscv64_user_regs, tid)); + + g_guest_arch = Architecture::RISCV64; + break; + } +#endif + default: + break; + } +} + int main(int argc, char** argv) { DefuseSignalHandlers(); InstallSigPipeHandler(); @@ -551,6 +668,7 @@ int main(int argc, char** argv) { continue; } } + ReadGuestRegisters(&info.guest_registers, thread); thread_info[thread] = std::move(info); } @@ -660,8 +778,32 @@ int main(int argc, char** argv) { { ATRACE_NAME("engrave_tombstone"); - engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info, - g_target_thread, process_info, &open_files, &amfd_data); + unwindstack::ArchEnum regs_arch = unwindstack::ARCH_UNKNOWN; + switch (g_guest_arch) { + case Architecture::ARM32: { + regs_arch = unwindstack::ARCH_ARM; + break; + } + case Architecture::ARM64: { + regs_arch = unwindstack::ARCH_ARM64; + break; + } + case Architecture::RISCV64: { + regs_arch = unwindstack::ARCH_RISCV64; + break; + } + default: { + } + } + if (regs_arch == unwindstack::ARCH_UNKNOWN) { + engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info, + g_target_thread, process_info, &open_files, &amfd_data); + } else { + unwindstack::AndroidRemoteUnwinder guest_unwinder(vm_pid, regs_arch); + engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info, + g_target_thread, process_info, &open_files, &amfd_data, &g_guest_arch, + &guest_unwinder); + } } } diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp index 3b52776d7..05143ed05 100644 --- a/debuggerd/crasher/crasher.cpp +++ b/debuggerd/crasher/crasher.cpp @@ -202,7 +202,9 @@ static int usage() { fprintf(stderr, " fdsan_file close a file descriptor that's owned by a FILE*\n"); fprintf(stderr, " fdsan_dir close a file descriptor that's owned by a DIR*\n"); fprintf(stderr, " seccomp fail a seccomp check\n"); +#if defined(__LP64__) fprintf(stderr, " xom read execute-only memory\n"); +#endif fprintf(stderr, "\n"); fprintf(stderr, " LOG_ALWAYS_FATAL call liblog LOG_ALWAYS_FATAL\n"); fprintf(stderr, " LOG_ALWAYS_FATAL_IF call liblog LOG_ALWAYS_FATAL_IF\n"); diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index e4e2f99cc..baddf6578 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -332,12 +332,7 @@ TEST_F(CrasherTest, smoke) { std::string result; ConsumeFd(std::move(output_fd), &result); -#ifdef __LP64__ - ASSERT_MATCH(result, - R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)"); -#else - ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)"); -#endif + ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)"); if (mte_supported()) { // Test that the default TAGGED_ADDR_CTRL value is set. @@ -1829,10 +1824,14 @@ GwpAsanTestParameters gwp_asan_tests[] = { "Use After Free, 0 bytes into a 7-byte allocation"}, {/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1, "Use After Free, 1 byte into a 15-byte allocation"}, - {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ 4098, - "Buffer Overflow, 2 bytes right of a 4096-byte allocation"}, - {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ -1, - "Buffer Underflow, 1 byte left of a 4096-byte allocation"}, + {/* alloc_size */ static_cast<size_t>(getpagesize()), /* free_before_access */ false, + /* access_offset */ getpagesize() + 2, + android::base::StringPrintf("Buffer Overflow, 2 bytes right of a %d-byte allocation", + getpagesize())}, + {/* alloc_size */ static_cast<size_t>(getpagesize()), /* free_before_access */ false, + /* access_offset */ -1, + android::base::StringPrintf("Buffer Underflow, 1 byte left of a %d-byte allocation", + getpagesize())}, }; INSTANTIATE_TEST_SUITE_P( @@ -2977,30 +2976,34 @@ TEST_F(CrasherTest, verify_map_format) { std::string match_str; // Verify none. match_str = android::base::StringPrintf( - " %s-%s --- 0 1000\\n", + " %s-%s --- 0 %x\\n", format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(), - format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str()); + format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str(), + getpagesize()); ASSERT_MATCH(result, match_str); // Verify read-only. match_str = android::base::StringPrintf( - " %s-%s r-- 0 1000\\n", + " %s-%s r-- 0 %x\\n", format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(), - format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str()); + format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str(), + getpagesize()); ASSERT_MATCH(result, match_str); // Verify write-only. match_str = android::base::StringPrintf( - " %s-%s -w- 0 1000\\n", + " %s-%s -w- 0 %x\\n", format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(), - format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str()); + format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str(), + getpagesize()); ASSERT_MATCH(result, match_str); // Verify exec-only. match_str = android::base::StringPrintf( - " %s-%s --x 0 1000\\n", + " %s-%s --x 0 %x\\n", format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(), - format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str()); + format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str(), + getpagesize()); ASSERT_MATCH(result, match_str); // Verify file map with non-zero offset and a name. diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h index a506859a4..89bf5a96d 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h @@ -16,6 +16,8 @@ #pragma once +#if defined(USE_SCUDO) + #include "types.h" #include "utility.h" @@ -49,3 +51,5 @@ class ScudoCrashData { void FillInCause(Cause* cause, const scudo_error_report* report, unwindstack::AndroidUnwinder* unwinder) const; }; + +#endif // USE_SCUDO diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h index be999e04e..dfdfabdff 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h @@ -28,6 +28,7 @@ #include <android-base/unique_fd.h> #include "open_files_list.h" +#include "tombstone.pb.h" #include "types.h" // Forward declarations @@ -54,14 +55,17 @@ void engrave_tombstone(android::base::unique_fd output_fd, android::base::unique unwindstack::AndroidUnwinder* unwinder, const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread, const ProcessInfo& process_info, OpenFilesList* open_files, - std::string* amfd_data); + std::string* amfd_data, const Architecture* guest_arch = nullptr, + unwindstack::AndroidUnwinder* guest_unwinder = nullptr); void engrave_tombstone_ucontext(int tombstone_fd, int proto_fd, uint64_t abort_msg_address, siginfo_t* siginfo, ucontext_t* ucontext); void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder, const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread, - const ProcessInfo& process_info, const OpenFilesList* open_files); + const ProcessInfo& process_info, const OpenFilesList* open_files, + const Architecture* guest_arch, + unwindstack::AndroidUnwinder* guest_unwinder); bool tombstone_proto_to_text( const Tombstone& tombstone, diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h index 4d69658e2..c799f2448 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h @@ -39,6 +39,8 @@ struct ThreadInfo { int signo = 0; siginfo_t* siginfo = nullptr; + + std::unique_ptr<unwindstack::Regs> guest_registers; }; // This struct is written into a pipe from inside the crashing process. diff --git a/debuggerd/libdebuggerd/scudo.cpp b/debuggerd/libdebuggerd/scudo.cpp index 3fa3bd032..4ee87c841 100644 --- a/debuggerd/libdebuggerd/scudo.cpp +++ b/debuggerd/libdebuggerd/scudo.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#if defined(USE_SCUDO) + #include "libdebuggerd/scudo.h" #include "libdebuggerd/tombstone.h" @@ -141,3 +143,5 @@ void ScudoCrashData::AddCauseProtos(Tombstone* tombstone, FillInCause(tombstone->add_causes(), &error_info_.reports[report_num++], unwinder); } } + +#endif // USE_SCUDO diff --git a/debuggerd/libdebuggerd/test/dump_memory_test.cpp b/debuggerd/libdebuggerd/test/dump_memory_test.cpp index 5be145aad..dee7b4827 100644 --- a/debuggerd/libdebuggerd/test/dump_memory_test.cpp +++ b/debuggerd/libdebuggerd/test/dump_memory_test.cpp @@ -20,6 +20,8 @@ #include <string> #include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/stringprintf.h> #include <gtest/gtest.h> #include <unwindstack/Memory.h> @@ -27,61 +29,64 @@ #include "log_fake.h" -const char g_expected_full_dump[] = -"\nmemory near r1:\n" +std::string GetMemoryString(uintptr_t addr, const std::vector<uint64_t>& data) { + // Must be even number of data values. + CHECK((data.size() & 1) == 0); + + std::string str; + for (size_t i = 0; i < data.size(); i += 2) { + str += " "; + std::string ascii_str = ""; + for (size_t j = 0; j < 2; j++) { + for (size_t k = 0; k < 8; k++) { + uint8_t c = (data[i + j] >> (k * 8)) & 0xff; + if (c >= 0x20 && c < 0x7f) { + ascii_str += c; + } else { + ascii_str += '.'; + } + } + } #if defined(__LP64__) -" 0000000012345650 0706050403020100 0f0e0d0c0b0a0908 ................\n" -" 0000000012345660 1716151413121110 1f1e1d1c1b1a1918 ................\n" -" 0000000012345670 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" -" 0000000012345680 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" -" 0000000012345690 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" -" 00000000123456a0 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" -" 00000000123456b0 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n" -" 00000000123456c0 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n" -" 00000000123456d0 8786858483828180 8f8e8d8c8b8a8988 ................\n" -" 00000000123456e0 9796959493929190 9f9e9d9c9b9a9998 ................\n" -" 00000000123456f0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" -" 0000000012345700 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" -" 0000000012345710 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" -" 0000000012345720 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" -" 0000000012345730 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" -" 0000000012345740 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; + str += android::base::StringPrintf("%016zx %016zx %016zx ", addr, data[i], data[i + 1]); #else -" 12345650 03020100 07060504 0b0a0908 0f0e0d0c ................\n" -" 12345660 13121110 17161514 1b1a1918 1f1e1d1c ................\n" -" 12345670 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n" -" 12345680 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n" -" 12345690 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n" -" 123456a0 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n" -" 123456b0 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n" -" 123456c0 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n" -" 123456d0 83828180 87868584 8b8a8988 8f8e8d8c ................\n" -" 123456e0 93929190 97969594 9b9a9998 9f9e9d9c ................\n" -" 123456f0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n" -" 12345700 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n" -" 12345710 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" -" 12345720 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" -" 12345730 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n" -" 12345740 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n"; + str += android::base::StringPrintf( + "%08zx %08zx %08zx %08zx %08zx ", addr, static_cast<uintptr_t>(data[i] & 0xffffffff), + static_cast<uintptr_t>(data[i] >> 32), static_cast<uintptr_t>(data[i + 1] & 0xffffffff), + static_cast<uintptr_t>(data[i + 1] >> 32)); #endif + str += ascii_str + "\n"; + addr += 0x10; + } + return str; +} -const char g_expected_partial_dump[] = \ -"\nmemory near pc:\n" -#if defined(__LP64__) -" 00000000123455e0 0706050403020100 0f0e0d0c0b0a0908 ................\n" -" 00000000123455f0 1716151413121110 1f1e1d1c1b1a1918 ................\n" -" 0000000012345600 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" -" 0000000012345610 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" -" 0000000012345620 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" -" 0000000012345630 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"; -#else -" 123455e0 03020100 07060504 0b0a0908 0f0e0d0c ................\n" -" 123455f0 13121110 17161514 1b1a1918 1f1e1d1c ................\n" -" 12345600 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n" -" 12345610 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n" -" 12345620 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n" -" 12345630 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"; -#endif +const std::vector<uint64_t>& GetDefaultData() { + static std::vector<uint64_t> data( + {0x0706050403020100UL, 0x0f0e0d0c0b0a0908UL, 0x1716151413121110UL, 0x1f1e1d1c1b1a1918UL, + 0x2726252423222120UL, 0x2f2e2d2c2b2a2928UL, 0x3736353433323130UL, 0x3f3e3d3c3b3a3938UL, + 0x4746454443424140UL, 0x4f4e4d4c4b4a4948UL, 0x5756555453525150UL, 0x5f5e5d5c5b5a5958UL, + 0x6766656463626160UL, 0x6f6e6d6c6b6a6968UL, 0x7776757473727170UL, 0x7f7e7d7c7b7a7978UL, + 0x8786858483828180UL, 0x8f8e8d8c8b8a8988UL, 0x9796959493929190UL, 0x9f9e9d9c9b9a9998UL, + 0xa7a6a5a4a3a2a1a0UL, 0xafaeadacabaaa9a8UL, 0xb7b6b5b4b3b2b1b0UL, 0xbfbebdbcbbbab9b8UL, + 0xc7c6c5c4c3c2c1c0UL, 0xcfcecdcccbcac9c8UL, 0xd7d6d5d4d3d2d1d0UL, 0xdfdedddcdbdad9d8UL, + 0xe7e6e5e4e3e2e1e0UL, 0xefeeedecebeae9e8UL, 0xf7f6f5f4f3f2f1f0UL, 0xfffefdfcfbfaf9f8UL}); + return data; +} + +std::string GetFullDumpString() { + std::string str = "\nmemory near r1:\n"; + str += GetMemoryString(0x12345650U, GetDefaultData()); + return str; +} + +std::string GetPartialDumpString() { + std::string str = "\nmemory near pc:\n"; + std::vector<uint64_t> data = GetDefaultData(); + data.resize(12); + str += GetMemoryString(0x123455e0U, data); + return str; +} class MemoryMock : public unwindstack::Memory { public: @@ -189,7 +194,7 @@ TEST_F(DumpMemoryTest, aligned_addr) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str()); + ASSERT_EQ(GetFullDumpString(), tombstone_contents); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -209,7 +214,7 @@ TEST_F(DumpMemoryTest, partial_read) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str()); + ASSERT_EQ(GetFullDumpString(), tombstone_contents); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -228,7 +233,7 @@ TEST_F(DumpMemoryTest, unaligned_addr) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str()); + ASSERT_EQ(GetFullDumpString(), tombstone_contents); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -260,7 +265,7 @@ TEST_F(DumpMemoryTest, memory_partially_unreadable) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str()); + ASSERT_EQ(GetPartialDumpString(), tombstone_contents); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -280,7 +285,7 @@ TEST_F(DumpMemoryTest, memory_partially_unreadable_unaligned_return) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str()); + ASSERT_EQ(GetPartialDumpString(), tombstone_contents); #if defined(__LP64__) ASSERT_STREQ("6 DEBUG Bytes read 102, is not a multiple of 8\n", getFakeLogPrint().c_str()); @@ -305,7 +310,7 @@ TEST_F(DumpMemoryTest, memory_partially_unreadable_two_unaligned_reads) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str()); + ASSERT_EQ(GetPartialDumpString(), tombstone_contents); #if defined(__LP64__) ASSERT_STREQ("6 DEBUG Bytes read 45, is not a multiple of 8\n" @@ -331,44 +336,9 @@ TEST_F(DumpMemoryTest, address_low_fence) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - const char* expected_dump = \ -"\nmemory near r1:\n" -#if defined(__LP64__) -" 0000000000001000 0000000000000000 0000000000000000 ................\n" -" 0000000000001010 0000000000000000 0000000000000000 ................\n" -" 0000000000001020 0000000000000000 0000000000000000 ................\n" -" 0000000000001030 0000000000000000 0000000000000000 ................\n" -" 0000000000001040 0000000000000000 0000000000000000 ................\n" -" 0000000000001050 0000000000000000 0000000000000000 ................\n" -" 0000000000001060 0000000000000000 0000000000000000 ................\n" -" 0000000000001070 0000000000000000 0000000000000000 ................\n" -" 0000000000001080 0000000000000000 0000000000000000 ................\n" -" 0000000000001090 0000000000000000 0000000000000000 ................\n" -" 00000000000010a0 0000000000000000 0000000000000000 ................\n" -" 00000000000010b0 0000000000000000 0000000000000000 ................\n" -" 00000000000010c0 0000000000000000 0000000000000000 ................\n" -" 00000000000010d0 0000000000000000 0000000000000000 ................\n" -" 00000000000010e0 0000000000000000 0000000000000000 ................\n" -" 00000000000010f0 0000000000000000 0000000000000000 ................\n"; -#else -" 00001000 00000000 00000000 00000000 00000000 ................\n" -" 00001010 00000000 00000000 00000000 00000000 ................\n" -" 00001020 00000000 00000000 00000000 00000000 ................\n" -" 00001030 00000000 00000000 00000000 00000000 ................\n" -" 00001040 00000000 00000000 00000000 00000000 ................\n" -" 00001050 00000000 00000000 00000000 00000000 ................\n" -" 00001060 00000000 00000000 00000000 00000000 ................\n" -" 00001070 00000000 00000000 00000000 00000000 ................\n" -" 00001080 00000000 00000000 00000000 00000000 ................\n" -" 00001090 00000000 00000000 00000000 00000000 ................\n" -" 000010a0 00000000 00000000 00000000 00000000 ................\n" -" 000010b0 00000000 00000000 00000000 00000000 ................\n" -" 000010c0 00000000 00000000 00000000 00000000 ................\n" -" 000010d0 00000000 00000000 00000000 00000000 ................\n" -" 000010e0 00000000 00000000 00000000 00000000 ................\n" -" 000010f0 00000000 00000000 00000000 00000000 ................\n"; -#endif - ASSERT_STREQ(expected_dump, tombstone_contents.c_str()); + std::string expected_dump = "\nmemory near r1:\n"; + expected_dump += GetMemoryString(0x1000, std::vector<uint64_t>(32, 0UL)); + ASSERT_EQ(expected_dump, tombstone_contents); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -414,61 +384,17 @@ TEST_F(DumpMemoryTest, memory_address_nearly_too_high) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - const char* expected_dump = \ -"\nmemory near r4:\n" + std::string expected_dump = "\nmemory near r4:\n"; + uintptr_t addr; #if defined(__aarch64__) -" 00ffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n" -" 00ffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n" -" 00ffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" -" 00ffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" -" 00ffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" -" 00ffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" -" 00ffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n" -" 00ffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n" -" 00ffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n" -" 00ffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n" -" 00ffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" -" 00ffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" -" 00ffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" -" 00ffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" -" 00ffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" -" 00fffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; + addr = 0x00ffffffffffff00UL; #elif defined(__LP64__) -" ffffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n" -" ffffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n" -" ffffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" -" ffffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" -" ffffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" -" ffffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" -" ffffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n" -" ffffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n" -" ffffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n" -" ffffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n" -" ffffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" -" ffffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" -" ffffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" -" ffffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" -" ffffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" -" fffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; + addr = 0xffffffffffffff00UL; #else -" ffffff00 03020100 07060504 0b0a0908 0f0e0d0c ................\n" -" ffffff10 13121110 17161514 1b1a1918 1f1e1d1c ................\n" -" ffffff20 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n" -" ffffff30 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n" -" ffffff40 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n" -" ffffff50 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n" -" ffffff60 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n" -" ffffff70 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n" -" ffffff80 83828180 87868584 8b8a8988 8f8e8d8c ................\n" -" ffffff90 93929190 97969594 9b9a9998 9f9e9d9c ................\n" -" ffffffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n" -" ffffffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n" -" ffffffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" -" ffffffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" -" ffffffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n" -" fffffff0 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n"; + addr = 0xffffff00UL; #endif - ASSERT_STREQ(expected_dump, tombstone_contents.c_str()); + expected_dump += GetMemoryString(addr, GetDefaultData()); + ASSERT_EQ(expected_dump, tombstone_contents); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -490,30 +416,15 @@ TEST_F(DumpMemoryTest, first_read_empty) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - const char* expected_dump = \ -"\nmemory near r4:\n" -#if defined(__LP64__) -R"( 0000000010001000 8786858483828180 8f8e8d8c8b8a8988 ................ - 0000000010001010 9796959493929190 9f9e9d9c9b9a9998 ................ - 0000000010001020 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................ - 0000000010001030 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................ - 0000000010001040 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................ - 0000000010001050 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................ - 0000000010001060 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................ - 0000000010001070 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................ -)"; -#else -R"( 10001000 83828180 87868584 8b8a8988 8f8e8d8c ................ - 10001010 93929190 97969594 9b9a9998 9f9e9d9c ................ - 10001020 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................ - 10001030 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................ - 10001040 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................ - 10001050 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................ - 10001060 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................ - 10001070 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................ -)"; -#endif - ASSERT_STREQ(expected_dump, tombstone_contents.c_str()); + std::string expected_dump = "\nmemory near r4:\n"; + expected_dump += GetMemoryString( + 0x10000000 + page_size, + std::vector<uint64_t>{ + 0x8786858483828180UL, 0x8f8e8d8c8b8a8988UL, 0x9796959493929190UL, 0x9f9e9d9c9b9a9998UL, + 0xa7a6a5a4a3a2a1a0UL, 0xafaeadacabaaa9a8UL, 0xb7b6b5b4b3b2b1b0UL, 0xbfbebdbcbbbab9b8UL, + 0xc7c6c5c4c3c2c1c0UL, 0xcfcecdcccbcac9c8UL, 0xd7d6d5d4d3d2d1d0UL, 0xdfdedddcdbdad9d8UL, + 0xe7e6e5e4e3e2e1e0UL, 0xefeeedecebeae9e8UL, 0xf7f6f5f4f3f2f1f0UL, 0xfffefdfcfbfaf9f8UL}); + ASSERT_EQ(expected_dump, tombstone_contents); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -535,16 +446,11 @@ TEST_F(DumpMemoryTest, first_read_empty_second_read_stops) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - const char* expected_dump = \ -"\nmemory near r4:\n" -#if defined(__LP64__) -" 0000000010001000 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" -" 0000000010001010 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"; -#else -" 10001000 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" -" 10001010 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"; -#endif - ASSERT_STREQ(expected_dump, tombstone_contents.c_str()); + std::string expected_dump = "\nmemory near r4:\n"; + expected_dump += GetMemoryString( + 0x10000000 + page_size, std::vector<uint64_t>{0xc7c6c5c4c3c2c1c0UL, 0xcfcecdcccbcac9c8UL, + 0xd7d6d5d4d3d2d1d0UL, 0xdfdedddcdbdad9d8UL}); + ASSERT_EQ(expected_dump, tombstone_contents); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index 5a416d643..0ce55738a 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -125,10 +125,12 @@ void engrave_tombstone(unique_fd output_fd, unique_fd proto_fd, unwindstack::AndroidUnwinder* unwinder, const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread, const ProcessInfo& process_info, OpenFilesList* open_files, - std::string* amfd_data) { + std::string* amfd_data, const Architecture* guest_arch, + unwindstack::AndroidUnwinder* guest_unwinder) { // Don't copy log messages to tombstone unless this is a development device. Tombstone tombstone; - engrave_tombstone_proto(&tombstone, unwinder, threads, target_thread, process_info, open_files); + engrave_tombstone_proto(&tombstone, unwinder, threads, target_thread, process_info, open_files, + guest_arch, guest_unwinder); if (proto_fd != -1) { if (!tombstone.SerializeToFileDescriptor(proto_fd.get())) { diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index 4cde98610..3e8ab6ea5 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -482,7 +482,8 @@ static void dump_thread_backtrace(std::vector<unwindstack::FrameData>& frames, T } static void dump_thread(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder, - const ThreadInfo& thread_info, bool memory_dump = false) { + const ThreadInfo& thread_info, bool memory_dump = false, + unwindstack::AndroidUnwinder* guest_unwinder = nullptr) { Thread thread; thread.set_id(thread_info.tid); @@ -509,6 +510,27 @@ static void dump_thread(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwi auto& threads = *tombstone->mutable_threads(); threads[thread_info.tid] = thread; + + if (guest_unwinder) { + if (!thread_info.guest_registers) { + async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, + "No guest state registers information for tid %d", thread_info.tid); + return; + } + Thread guest_thread; + unwindstack::AndroidUnwinderData guest_data; + guest_data.saved_initial_regs = std::make_optional<std::unique_ptr<unwindstack::Regs>>(); + if (guest_unwinder->Unwind(thread_info.guest_registers.get(), guest_data)) { + dump_thread_backtrace(guest_data.frames, guest_thread); + } else { + async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, + "Unwind guest state registers failed for tid %d: Error %s", + thread_info.tid, guest_data.GetErrorString().c_str()); + } + dump_registers(guest_unwinder, *guest_data.saved_initial_regs, guest_thread, memory_dump); + auto& guest_threads = *tombstone->mutable_guest_threads(); + guest_threads[thread_info.tid] = guest_thread; + } } static void dump_mappings(Tombstone* tombstone, unwindstack::Maps* maps, @@ -686,10 +708,17 @@ static void dump_tags_around_fault_addr(Signal* signal, const Tombstone& tombsto void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder, const std::map<pid_t, ThreadInfo>& threads, pid_t target_tid, - const ProcessInfo& process_info, const OpenFilesList* open_files) { + const ProcessInfo& process_info, const OpenFilesList* open_files, + const Architecture* guest_arch, + unwindstack::AndroidUnwinder* guest_unwinder) { Tombstone result; result.set_arch(get_arch()); + if (guest_arch != nullptr) { + result.set_guest_arch(*guest_arch); + } else { + result.set_guest_arch(Architecture::NONE); + } result.set_build_fingerprint(android::base::GetProperty("ro.build.fingerprint", "unknown")); result.set_revision(android::base::GetProperty("ro.revision", "unknown")); result.set_timestamp(get_timestamp()); @@ -714,6 +743,9 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* error.c_str()); } + result.set_page_size(getpagesize()); + result.set_has_been_16kb_mode(android::base::GetBoolProperty("ro.misctrl.16kb_before", false)); + auto cmd_line = result.mutable_command_line(); for (const auto& arg : target_thread.command_line) { *cmd_line->Add() = arg; @@ -747,11 +779,11 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* dump_abort_message(&result, unwinder->GetProcessMemory(), process_info); dump_crash_details(&result, unwinder->GetProcessMemory(), process_info); // Dump the target thread, but save the memory around the registers. - dump_thread(&result, unwinder, target_thread, /* memory_dump */ true); + dump_thread(&result, unwinder, target_thread, /* memory_dump */ true, guest_unwinder); for (const auto& [tid, thread_info] : threads) { if (tid != target_tid) { - dump_thread(&result, unwinder, thread_info); + dump_thread(&result, unwinder, thread_info, /* memory_dump */ false, guest_unwinder); } } diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp index cefa2d62e..19007194e 100644 --- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp @@ -79,8 +79,8 @@ static std::string describe_pac_enabled_keys(long value) { return describe_end(value, desc); } -static const char* abi_string(const Tombstone& tombstone) { - switch (tombstone.arch()) { +static const char* abi_string(const Architecture& arch) { + switch (arch) { case Architecture::ARM32: return "arm"; case Architecture::ARM64: @@ -578,14 +578,38 @@ void print_logs(CallbackType callback, const Tombstone& tombstone, int tail) { } } +static void print_guest_thread(CallbackType callback, const Tombstone& tombstone, + const Thread& guest_thread, pid_t tid, bool should_log) { + CBS("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---"); + CBS("Guest thread information for tid: %d", tid); + print_thread_registers(callback, tombstone, guest_thread, should_log); + + CBS(""); + CB(true, "%d total frames", guest_thread.current_backtrace().size()); + CB(true, "backtrace:"); + print_backtrace(callback, tombstone, guest_thread.current_backtrace(), should_log); + + print_thread_memory_dump(callback, tombstone, guest_thread); +} + bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback) { CBL("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***"); CBL("Build fingerprint: '%s'", tombstone.build_fingerprint().c_str()); CBL("Revision: '%s'", tombstone.revision().c_str()); - CBL("ABI: '%s'", abi_string(tombstone)); + CBL("ABI: '%s'", abi_string(tombstone.arch())); + if (tombstone.guest_arch() != Architecture::NONE) { + CBL("Guest architecture: '%s'", abi_string(tombstone.guest_arch())); + } CBL("Timestamp: %s", tombstone.timestamp().c_str()); CBL("Process uptime: %ds", tombstone.process_uptime()); + // only print this info if the page size is not 4k or has been in 16k mode + if (tombstone.page_size() != 4096) { + CBL("Page size: %d bytes", tombstone.page_size()); + } else if (tombstone.has_been_16kb_mode()) { + CBL("Has been in 16kb mode: yes"); + } + // Process header const auto& threads = tombstone.threads(); auto main_thread_it = threads.find(tombstone.tid()); @@ -600,6 +624,12 @@ bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback) print_logs(callback, tombstone, 50); + const auto& guest_threads = tombstone.guest_threads(); + auto main_guest_thread_it = guest_threads.find(tombstone.tid()); + if (main_guest_thread_it != threads.end()) { + print_guest_thread(callback, tombstone, main_guest_thread_it->second, tombstone.tid(), true); + } + // protobuf's map is unordered, so sort the keys first. std::set<int> thread_ids; for (const auto& [tid, _] : threads) { @@ -611,6 +641,10 @@ bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback) for (const auto& tid : thread_ids) { CBS("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---"); print_thread(callback, tombstone, threads.find(tid)->second); + auto guest_thread_it = guest_threads.find(tid); + if (guest_thread_it != guest_threads.end()) { + print_guest_thread(callback, tombstone, guest_thread_it->second, tid, false); + } } if (tombstone.open_fds().size() > 0) { diff --git a/debuggerd/proto/tombstone.proto b/debuggerd/proto/tombstone.proto index 214cbfb46..6f9cd9612 100644 --- a/debuggerd/proto/tombstone.proto +++ b/debuggerd/proto/tombstone.proto @@ -22,6 +22,7 @@ message CrashDetail { message Tombstone { Architecture arch = 1; + Architecture guest_arch = 24; string build_fingerprint = 2; string revision = 3; string timestamp = 4; @@ -42,11 +43,15 @@ message Tombstone { repeated Cause causes = 15; map<uint32, Thread> threads = 16; + map<uint32, Thread> guest_threads = 25; repeated MemoryMapping memory_mappings = 17; repeated LogBuffer log_buffers = 18; repeated FD open_fds = 19; - reserved 22 to 999; + uint32 page_size = 22; + bool has_been_16kb_mode = 23; + + reserved 26 to 999; } enum Architecture { @@ -55,8 +60,9 @@ enum Architecture { X86 = 2; X86_64 = 3; RISCV64 = 4; + NONE = 5; - reserved 5 to 999; + reserved 6 to 999; } message Signal { diff --git a/fs_mgr/liblp/fuzzer/Android.bp b/fs_mgr/liblp/fuzzer/Android.bp index a9e3509af..46bd03197 100644 --- a/fs_mgr/liblp/fuzzer/Android.bp +++ b/fs_mgr/liblp/fuzzer/Android.bp @@ -15,6 +15,10 @@ * */ +package { + default_team: "trendy_team_android_kernel", +} + cc_defaults { name: "liblp_fuzz_defaults", header_libs: [ @@ -33,7 +37,7 @@ cc_defaults { ], fuzz_config: { cc: [ - "android-media-fuzzing-reports@google.com", + "android-systems-storage@google.com", ], componentid: 59148, hotlists: ["4593311"], @@ -41,8 +45,8 @@ cc_defaults { vector: "local_no_privileges_required", service_privilege: "privileged", users: "multi_user", - fuzzed_code_usage: "shipped" - } + fuzzed_code_usage: "shipped", + }, } cc_fuzz { @@ -196,6 +200,6 @@ cc_fuzz { ":test_vendor_boot_v4_with_frag", ], cflags: [ - "-Wno-unused-parameter", - ], + "-Wno-unused-parameter", + ], } diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp index 95398e4b9..1117ec965 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp @@ -731,7 +731,8 @@ bool CowWriterV3::WriteOperation(std::span<const CowOperationV3> ops, i += chunk; } if (total_written != total_data_size) { - PLOG(ERROR) << "write failed for data of size: " << data.size() + PLOG(ERROR) << "write failed for data vector of size: " << data.size() + << " and total data length: " << total_data_size << " at offset: " << next_data_pos_ << " " << errno << ", only wrote: " << total_written; return false; diff --git a/init/Android.bp b/init/Android.bp index 4332e03bb..6160a713d 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -326,7 +326,7 @@ cc_binary { recovery_available: false, static_libs: ["libinit.microdroid"], cflags: ["-DMICRODROID=1"], - installable: false, + no_full_install: true, visibility: ["//packages/modules/Virtualization/microdroid"], } @@ -476,7 +476,7 @@ cc_binary { "init_first_stage_defaults", ], cflags: ["-DMICRODROID=1"], - installable: false, + no_full_install: true, } phony { diff --git a/init/property_service.cpp b/init/property_service.cpp index d3cdd437f..cd5933d23 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -974,6 +974,17 @@ static std::string ConstructBuildFingerprint(bool legacy) { std::string build_fingerprint = GetProperty("ro.product.brand", UNKNOWN); build_fingerprint += '/'; build_fingerprint += GetProperty("ro.product.name", UNKNOWN); + + // should be set in /product/etc/build.prop + // when we have a dev option device, and we've switched the kernel to 16kb mode + // we use the same system image, but we've switched out the kernel, so make it + // visible at a high level + bool has16KbDevOption = + android::base::GetBoolProperty("ro.product.build.16k_page.enabled", false); + if (has16KbDevOption && getpagesize() == 16384) { + build_fingerprint += "_16kb"; + } + build_fingerprint += '/'; build_fingerprint += GetProperty("ro.product.device", UNKNOWN); build_fingerprint += ':'; diff --git a/init/test_upgrade_mte/AndroidTest.xml b/init/test_upgrade_mte/AndroidTest.xml index b89cde8df..e08afc087 100644 --- a/init/test_upgrade_mte/AndroidTest.xml +++ b/init/test_upgrade_mte/AndroidTest.xml @@ -20,11 +20,13 @@ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> <option name="cleanup" value="true" /> <option name="remount-system" value="true" /> - <option name="push" value="mte_upgrade_test.rc->/system/etc/init/mte_upgrade_test.rc" /> - <option name="push" value="mte_upgrade_test_helper->/system/bin/mte_upgrade_test_helper" /> - <option name="push" value="mte_upgrade_test_helper->/data/local/tmp/app_process64" /> + + <option name="push-file" key="mte_upgrade_test.rc" value="/system/etc/init/mte_upgrade_test.rc" /> + <option name="push-file" key="mte_upgrade_test_helper" value="/system/bin/mte_upgrade_test_helper" /> + <option name="push-file" key="mte_upgrade_test_helper" value="/data/local/tmp/app_process64" /> + <option name="post-push" value="chmod 644 /system/etc/init/mte_upgrade_test.rc" /> </target_preparer> <test class="com.android.tradefed.testtype.HostTest" > <option name="jar" value="mte_upgrade_test.jar" /> </test> -</configuration>
\ No newline at end of file +</configuration> diff --git a/init/test_upgrade_mte/OWNERS b/init/test_upgrade_mte/OWNERS new file mode 100644 index 000000000..79625dfb1 --- /dev/null +++ b/init/test_upgrade_mte/OWNERS @@ -0,0 +1,5 @@ +fmayer@google.com + +eugenis@google.com +mitchp@google.com +pcc@google.com diff --git a/init/test_upgrade_mte/mte_upgrade_test_helper.cpp b/init/test_upgrade_mte/mte_upgrade_test_helper.cpp index 6728cc6d0..c4b175adc 100644 --- a/init/test_upgrade_mte/mte_upgrade_test_helper.cpp +++ b/init/test_upgrade_mte/mte_upgrade_test_helper.cpp @@ -22,6 +22,7 @@ #include <sys/prctl.h> #include <time.h> #include <unistd.h> + #include <memory> int MaybeDowngrade() { @@ -65,7 +66,5 @@ int main(int argc, char** argv) { // This binary gets run by src/com/android/tests/init/MteUpgradeTest.java, which // asserts that it crashes as expected. f[17] = 'x'; - char buf[1]; - read(1, buf, 1); return 0; } diff --git a/init/util.cpp b/init/util.cpp index e5efc7da6..375e905d5 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -570,6 +570,8 @@ Result<std::pair<int, std::vector<std::string>>> ParseRestorecon( {"--recursive", SELINUX_ANDROID_RESTORECON_RECURSE}, {"--skip-ce", SELINUX_ANDROID_RESTORECON_SKIPCE}, {"--cross-filesystems", SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS}, + {"--force", SELINUX_ANDROID_RESTORECON_FORCE}, + {"--data-data", SELINUX_ANDROID_RESTORECON_DATADATA}, {0, 0}}; int flag = 0; diff --git a/janitors/OWNERS b/janitors/OWNERS index a28737ebc..c25d9e465 100644 --- a/janitors/OWNERS +++ b/janitors/OWNERS @@ -3,4 +3,5 @@ ccross@google.com cferris@google.com dwillemsen@google.com enh@google.com +maco@google.com sadafebrahimi@google.com diff --git a/libstats/socket_lazy/Android.bp b/libstats/socket_lazy/Android.bp index b2cd7b26b..241e87af3 100644 --- a/libstats/socket_lazy/Android.bp +++ b/libstats/socket_lazy/Android.bp @@ -7,6 +7,12 @@ package { cc_library_static { name: "libstatssocket_lazy", + local_include_dirs: [ + "include", + ], + export_include_dirs: [ + "include", + ], header_libs: [ "libstatssocket_headers", ], @@ -28,7 +34,10 @@ cc_test { "-Wall", "-Werror", ], - test_suites: ["device-tests", "mts-statsd"], + test_suites: [ + "device-tests", + "mts-statsd", + ], test_config: "libstatssocket_lazy_test.xml", // TODO(b/153588990): Remove when the build system properly separates. // 32bit and 64bit architectures. diff --git a/libstats/socket_lazy/include/statssocket_lazy.h b/libstats/socket_lazy/include/statssocket_lazy.h new file mode 100644 index 000000000..7dda0bac4 --- /dev/null +++ b/libstats/socket_lazy/include/statssocket_lazy.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace android::statssocket::lazy { + +// See if libstatssocket.so is available. Early processes relying on _lazy might not have access +// to libstatssocket.so when they start before the StatsD APEX is available. +bool IsAvailable(); + +} // namespace android::statssocket::lazy diff --git a/libstats/socket_lazy/libstatssocket_lazy.cpp b/libstats/socket_lazy/libstatssocket_lazy.cpp index fe94ef2d8..d907c7e27 100644 --- a/libstats/socket_lazy/libstatssocket_lazy.cpp +++ b/libstats/socket_lazy/libstatssocket_lazy.cpp @@ -23,8 +23,10 @@ #include "log/log.h" -#include "stats_event.h" -#include "stats_socket.h" +#include <stats_event.h> +#include <stats_socket.h> + +#include "statssocket_lazy.h" // This file provides a lazy interface to libstatssocket.so to address early boot dependencies. // Specifically bootanimation, surfaceflinger, and lmkd run before the statsd APEX is loaded and @@ -77,6 +79,13 @@ static void* LoadLibstatssocket(int dlopen_flags) { return dlopen("libstatssocket.so", dlopen_flags); } +namespace android::statssocket::lazy { +bool IsAvailable() { + static const void* handle = LoadLibstatssocket(RTLD_NOW); + return handle != nullptr; +} +} // namespace android::statssocket::lazy + // // Initialization and symbol binding. diff --git a/libstats/socket_lazy/tests/libstatssocket_lazy_test.cpp b/libstats/socket_lazy/tests/libstatssocket_lazy_test.cpp index 3de6cd762..733f1e41c 100644 --- a/libstats/socket_lazy/tests/libstatssocket_lazy_test.cpp +++ b/libstats/socket_lazy/tests/libstatssocket_lazy_test.cpp @@ -21,6 +21,8 @@ #include "stats_event.h" #include "stats_socket.h" +#include "statssocket_lazy.h" + // The tests here are just for the case when libstatssocket.so cannot be loaded by // libstatssocket_lazy. class LibstatssocketLazyTest : public ::testing::Test { @@ -57,3 +59,7 @@ TEST_F(LibstatssocketLazyTest, NoLibstatssocketForStatsEvent) { TEST_F(LibstatssocketLazyTest, NoLibstatssocketForStatsSocket) { EXPECT_DEATH(AStatsSocket_close(), kLoadFailed); } + +TEST_F(LibstatssocketLazyTest, IsAvailableFalse) { + EXPECT_FALSE(android::statssocket::lazy::IsAvailable()); +} diff --git a/libutils/binder/String16_test.cpp b/libutils/binder/String16_test.cpp index 6f4642e8f..83cc5990b 100644 --- a/libutils/binder/String16_test.cpp +++ b/libutils/binder/String16_test.cpp @@ -16,6 +16,8 @@ #include <utils/String16.h> #include <utils/String8.h> +#include <compare> +#include <utility> #include <gtest/gtest.h> @@ -257,3 +259,45 @@ TEST(String16Test, insert) { EXPECT_EQ(NO_MEMORY, s.insert(3, u"", SIZE_MAX)); EXPECT_STR16EQ(u"foo!bar", s.c_str()); } + +TEST(String16Test, comparisons) { + const char16_t* cstr1 = u"abc"; + const char16_t* cstr2 = u"def"; + + // str1 and str1b will point to different blocks of memory but with equal contents. + String16 str1(cstr1); + String16 str1b(cstr1); + String16 str2(cstr2); + + EXPECT_TRUE((str1 <=> str1b) == 0); + EXPECT_FALSE(str1 != str1b); + EXPECT_FALSE(str1 < str1b); + EXPECT_TRUE(str1 <= str1b); + EXPECT_TRUE(str1 == str1b); + EXPECT_TRUE(str1 >= str1b); + EXPECT_FALSE(str1 > str1b); + + EXPECT_TRUE((str1 <=> str2) < 0); + EXPECT_TRUE((str2 <=> str1) > 0); + EXPECT_TRUE(str1 != str2); + EXPECT_TRUE(str1 < str2); + EXPECT_TRUE(str1 <= str2); + EXPECT_FALSE(str1 == str2); + EXPECT_FALSE(str1 >= str2); + EXPECT_FALSE(str1 > str2); + + // Verify that pre-C++20 comparison operators work with a std::pair of a String8, which only + // provides <=> in C++20 and up. See b/339775405. + + std::pair<String16, int> pair1(str1, 13); + std::pair<String16, int> pair1b(str1b, 13); + std::pair<String16, int> pair2(str2, 13); + + EXPECT_TRUE(pair1 == pair1b); + EXPECT_FALSE(pair1 < pair1b); + EXPECT_FALSE(pair1 > pair1b); + + EXPECT_TRUE(pair1 != pair2); + EXPECT_TRUE(pair1 < pair2); + EXPECT_FALSE(pair1 > pair2); +} diff --git a/libutils/binder/String8_test.cpp b/libutils/binder/String8_test.cpp index 6f7882a38..fc3c32941 100644 --- a/libutils/binder/String8_test.cpp +++ b/libutils/binder/String8_test.cpp @@ -17,8 +17,10 @@ #define LOG_TAG "String8_test" #include <log/log.h> -#include <utils/String8.h> #include <utils/String16.h> +#include <utils/String8.h> +#include <compare> +#include <utility> #include <gtest/gtest.h> @@ -132,3 +134,45 @@ TEST_F(String8Test, removeAll) { EXPECT_TRUE(s.removeAll("o")); EXPECT_STREQ("Hell, wrld!", s.c_str()); } + +TEST_F(String8Test, comparisons) { + const char* cstr1 = "abc"; + const char* cstr2 = "def"; + + // str1 and str1b will point to different blocks of memory but with equal contents. + String8 str1(cstr1); + String8 str1b(cstr1); + String8 str2(cstr2); + + EXPECT_TRUE((str1 <=> str1b) == 0); + EXPECT_FALSE(str1 != str1b); + EXPECT_FALSE(str1 < str1b); + EXPECT_TRUE(str1 <= str1b); + EXPECT_TRUE(str1 == str1b); + EXPECT_TRUE(str1 >= str1b); + EXPECT_FALSE(str1 > str1b); + + EXPECT_TRUE((str1 <=> str2) < 0); + EXPECT_TRUE((str2 <=> str1) > 0); + EXPECT_TRUE(str1 != str2); + EXPECT_TRUE(str1 < str2); + EXPECT_TRUE(str1 <= str2); + EXPECT_FALSE(str1 == str2); + EXPECT_FALSE(str1 >= str2); + EXPECT_FALSE(str1 > str2); + + // Verify that pre-C++20 comparison operators work with a std::pair of a String8, which only + // provides <=> in C++20 and up. See b/339775405. + + std::pair<String8, int> pair1(str1, 13); + std::pair<String8, int> pair1b(str1b, 13); + std::pair<String8, int> pair2(str2, 13); + + EXPECT_TRUE(pair1 == pair1b); + EXPECT_FALSE(pair1 < pair1b); + EXPECT_FALSE(pair1 > pair1b); + + EXPECT_TRUE(pair1 != pair2); + EXPECT_TRUE(pair1 < pair2); + EXPECT_FALSE(pair1 > pair2); +} diff --git a/libutils/binder/include/utils/String16.h b/libutils/binder/include/utils/String16.h index c7135766b..867dbac34 100644 --- a/libutils/binder/include/utils/String16.h +++ b/libutils/binder/include/utils/String16.h @@ -29,6 +29,10 @@ #define HAS_STRING_VIEW #endif +#if __cplusplus >= 202002L +#include <compare> +#endif + // --------------------------------------------------------------------------- namespace android { @@ -105,6 +109,9 @@ public: inline bool operator!=(const String16& other) const; inline bool operator>=(const String16& other) const; inline bool operator>(const String16& other) const; +#if __cplusplus >= 202002L + inline std::strong_ordering operator<=>(const String16& other) const; +#endif inline bool operator<(const char16_t* other) const; inline bool operator<=(const char16_t* other) const; @@ -112,6 +119,9 @@ public: inline bool operator!=(const char16_t* other) const; inline bool operator>=(const char16_t* other) const; inline bool operator>(const char16_t* other) const; +#if __cplusplus >= 202002L + inline std::strong_ordering operator<=>(const char16_t* other) const; +#endif inline operator const char16_t*() const; @@ -334,6 +344,19 @@ inline bool String16::operator>(const String16& other) const return strzcmp16(mString, size(), other.mString, other.size()) > 0; } +#if __cplusplus >= 202002L +inline std::strong_ordering String16::operator<=>(const String16& other) const { + int result = strzcmp16(mString, size(), other.mString, other.size()); + if (result == 0) { + return std::strong_ordering::equal; + } else if (result < 0) { + return std::strong_ordering::less; + } else { + return std::strong_ordering::greater; + } +} +#endif + inline bool String16::operator<(const char16_t* other) const { return strcmp16(mString, other) < 0; @@ -364,6 +387,19 @@ inline bool String16::operator>(const char16_t* other) const return strcmp16(mString, other) > 0; } +#if __cplusplus >= 202002L +inline std::strong_ordering String16::operator<=>(const char16_t* other) const { + int result = strcmp16(mString, other); + if (result == 0) { + return std::strong_ordering::equal; + } else if (result < 0) { + return std::strong_ordering::less; + } else { + return std::strong_ordering::greater; + } +} +#endif + inline String16::operator const char16_t*() const { return mString; diff --git a/libutils/binder/include/utils/String8.h b/libutils/binder/include/utils/String8.h index 6d250723b..e0d7588f6 100644 --- a/libutils/binder/include/utils/String8.h +++ b/libutils/binder/include/utils/String8.h @@ -36,6 +36,10 @@ #define HAS_STRING_VIEW #endif +#if __cplusplus >= 202002L +#include <compare> +#endif + // --------------------------------------------------------------------------- namespace android { @@ -106,6 +110,9 @@ public: inline bool operator!=(const String8& other) const; inline bool operator>=(const String8& other) const; inline bool operator>(const String8& other) const; +#if __cplusplus >= 202002L + inline std::strong_ordering operator<=>(const String8& other) const; +#endif inline bool operator<(const char* other) const; inline bool operator<=(const char* other) const; @@ -113,6 +120,9 @@ public: inline bool operator!=(const char* other) const; inline bool operator>=(const char* other) const; inline bool operator>(const char* other) const; +#if __cplusplus >= 202002L + inline std::strong_ordering operator<=>(const char* other) const; +#endif inline operator const char*() const; @@ -302,6 +312,19 @@ inline bool String8::operator>(const String8& other) const return strcmp(mString, other.mString) > 0; } +#if __cplusplus >= 202002L +inline std::strong_ordering String8::operator<=>(const String8& other) const { + int result = strcmp(mString, other.mString); + if (result == 0) { + return std::strong_ordering::equal; + } else if (result < 0) { + return std::strong_ordering::less; + } else { + return std::strong_ordering::greater; + } +} +#endif + inline bool String8::operator<(const char* other) const { return strcmp(mString, other) < 0; @@ -332,6 +355,19 @@ inline bool String8::operator>(const char* other) const return strcmp(mString, other) > 0; } +#if __cplusplus >= 202002L +inline std::strong_ordering String8::operator<=>(const char* other) const { + int result = strcmp(mString, other); + if (result == 0) { + return std::strong_ordering::equal; + } else if (result < 0) { + return std::strong_ordering::less; + } else { + return std::strong_ordering::greater; + } +} +#endif + inline String8::operator const char*() const { return mString; diff --git a/mkbootfs/mkbootfs.c b/mkbootfs/mkbootfs.c index d3922bf1a..84a0a4eee 100644 --- a/mkbootfs/mkbootfs.c +++ b/mkbootfs/mkbootfs.c @@ -402,7 +402,7 @@ static const struct option long_options[] = { static void usage(void) { fprintf(stderr, - "Usage: mkbootfs [-n FILE] [-d DIR|-F FILE] DIR...\n" + "Usage: mkbootfs [-n FILE] [-d DIR|-f FILE] DIR...\n" "\n" "\t-d, --dirname=DIR: fs-config directory\n" "\t-f, --file=FILE: Canned configuration file\n" @@ -410,11 +410,11 @@ static void usage(void) "\t-n, --nodes=FILE: Dev nodes description file\n" "\n" "Dev nodes description:\n" - "\t[dir|nod] [perms] [uid] [gid] [c|b] [minor] [major]\n" + "\t[dir|nod] [perms] [uid] [gid] [c|b] [major] [minor]\n" "\tExample:\n" "\t\t# My device nodes\n" "\t\tdir dev 0755 0 0\n" - "\t\tnod dev/null 0600 0 0 c 1 5\n" + "\t\tnod dev/null 0600 0 0 c 1 3\n" ); } @@ -445,11 +445,6 @@ int main(int argc, char *argv[]) int num_dirs = argc - optind; argv += optind; - if (num_dirs <= 0) { - usage(); - errx(1, "no directories to process?!"); - } - while(num_dirs-- > 0){ char *x = strchr(*argv, '='); if(x != 0) { diff --git a/rootdir/Android.bp b/rootdir/Android.bp index 06227c318..108c7c2e7 100644 --- a/rootdir/Android.bp +++ b/rootdir/Android.bp @@ -113,3 +113,7 @@ prebuilt_etc { src: "init-debug.rc", sub_dir: "init", } + +llndk_libraries_txt { + name: "llndk.libraries.txt", +} diff --git a/rootdir/init.rc b/rootdir/init.rc index f7f0cc385..e8b737d07 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -640,8 +640,7 @@ on post-fs mkdir /metadata/aconfig/boot 0775 root system mkdir /metadata/aconfig_test_missions 0775 root system - exec_start aconfigd-init - start aconfigd + exec_start aconfigd-platform-init on late-fs # Ensure that tracefs has the correct permissions. @@ -1031,6 +1030,8 @@ on post-fs-data # Wait for apexd to finish activating APEXes before starting more processes. wait_for_prop apexd.status activated perform_apex_config + exec_start aconfigd-mainline-init + start aconfigd # Create directories for boot animation. mkdir /data/misc/bootanim 0755 system system diff --git a/trusty/utils/coverage-controller/controller.cpp b/trusty/utils/coverage-controller/controller.cpp index 381a45285..f5d70b16d 100644 --- a/trusty/utils/coverage-controller/controller.cpp +++ b/trusty/utils/coverage-controller/controller.cpp @@ -60,6 +60,7 @@ void Controller::run(std::string output_dir) { filename.insert(0, output_dir); android::base::Result<void> res = record_list_[index]->SaveFile(filename); counters[index]++; + WRITE_ONCE(control->read_buffer_cnt, counters[index]); } if(complete_cnt == counters[index] && !(flags & FLAG_RUN)) { diff --git a/trusty/utils/coverage-controller/controller.h b/trusty/utils/coverage-controller/controller.h index f7789bfed..841a1aeb1 100644 --- a/trusty/utils/coverage-controller/controller.h +++ b/trusty/utils/coverage-controller/controller.h @@ -35,9 +35,9 @@ struct control { /* Written by controller, read by instrumented TA */ uint64_t cntrl_flags; + uint64_t read_buffer_cnt; /* Written by instrumented TA, read by controller */ - uint64_t oper_flags; uint64_t write_buffer_start_count; uint64_t write_buffer_complete_count; }; |