diff options
author | Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> | 2024-02-21 07:42:42 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2024-02-21 07:42:42 +0000 |
commit | 30c7aad06d283cdad3e7fe89f2addd517d58f16c (patch) | |
tree | 3e30664aefaa0c236a78bfde2ebf0512d6d79001 | |
parent | ca6861e8ad8c6c75402dc47d7685c638df70e114 (diff) | |
parent | ca4749af30608bf1893fde657b83a0a066250500 (diff) | |
download | bionic-30c7aad06d283cdad3e7fe89f2addd517d58f16c.tar.gz |
Merge changes from topics "crashapi2", "crashapi3" into main
* changes:
header and android_crash_detail prefix for crash_detail API
Allow to re-use the same crash_detail.
-rw-r--r-- | libc/Android.bp | 1 | ||||
-rw-r--r-- | libc/bionic/android_crash_detail.cpp | 122 | ||||
-rw-r--r-- | libc/bionic/android_set_abort_message.cpp | 65 | ||||
-rw-r--r-- | libc/include/android/crash_detail.h | 123 | ||||
-rw-r--r-- | libc/include/android/set_abort_message.h | 49 | ||||
-rw-r--r-- | libc/libc.map.txt | 6 | ||||
-rw-r--r-- | libc/platform/bionic/crash_detail_internal.h (renamed from libc/platform/bionic/set_abort_message_internal.h) | 2 |
7 files changed, 252 insertions, 116 deletions
diff --git a/libc/Android.bp b/libc/Android.bp index 071f309fa..7e5e972ee 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -791,6 +791,7 @@ cc_library_static { "bionic/abort.cpp", "bionic/accept.cpp", "bionic/access.cpp", + "bionic/android_crash_detail.cpp", "bionic/android_set_abort_message.cpp", "bionic/android_unsafe_frame_pointer_chase.cpp", "bionic/arpa_inet.cpp", diff --git a/libc/bionic/android_crash_detail.cpp b/libc/bionic/android_crash_detail.cpp new file mode 100644 index 000000000..30ce50565 --- /dev/null +++ b/libc/bionic/android_crash_detail.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <android/crash_detail.h> + +#include <async_safe/log.h> +#include <bionic/crash_detail_internal.h> + +#include <bits/stdatomic.h> +#include <pthread.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/prctl.h> + +#include "private/ScopedPthreadMutexLocker.h" +#include "private/bionic_defs.h" +#include "private/bionic_globals.h" + +static _Atomic(crash_detail_t*) free_head = nullptr; + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +crash_detail_t* android_crash_detail_register(const void* name, size_t name_size, const void* data, + size_t data_size) { + auto populate_crash_detail = [&](crash_detail_t* result) { + result->name = reinterpret_cast<const char*>(name); + result->name_size = name_size; + result->data = reinterpret_cast<const char*>(data); + result->data_size = data_size; + }; + // This is a atomic fast-path for RAII use-cases where the app keeps creating and deleting + // crash details for short periods of time to capture detailed scopes. + if (crash_detail_t* head = atomic_load(&free_head)) { + while (head != nullptr && !atomic_compare_exchange_strong(&free_head, &head, head->prev_free)) { + // intentionally left blank. + } + if (head) { + head->prev_free = nullptr; + populate_crash_detail(head); + return head; + } + } + ScopedPthreadMutexLocker locker(&__libc_shared_globals()->crash_detail_page_lock); + struct crash_detail_page_t* prev = nullptr; + struct crash_detail_page_t* page = __libc_shared_globals()->crash_detail_page; + if (page != nullptr && page->used == kNumCrashDetails) { + prev = page; + page = nullptr; + } + if (page == nullptr) { + size_t size = sizeof(crash_detail_page_t); + void* map = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (map == MAP_FAILED) { + async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to allocate crash_detail_page: %m"); + return nullptr; + } + prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map, size, "crash details"); + page = reinterpret_cast<struct crash_detail_page_t*>(map); + page->prev = prev; + __libc_shared_globals()->crash_detail_page = page; + } + crash_detail_t* result = &page->crash_details[page->used]; + populate_crash_detail(result); + page->used++; + return result; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void android_crash_detail_unregister(crash_detail_t* crash_detail) { + if (crash_detail) { + if (crash_detail->prev_free) { + // removing already removed would mess up the free-list by creating a circle. + return; + } + crash_detail->data = nullptr; + crash_detail->name = nullptr; + crash_detail_t* prev = atomic_load(&free_head); + do { + crash_detail->prev_free = prev; + } while (!atomic_compare_exchange_strong(&free_head, &prev, crash_detail)); + } +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void android_crash_detail_replace_data(crash_detail_t* crash_detail, const void* data, + size_t data_size) { + crash_detail->data = reinterpret_cast<const char*>(data); + crash_detail->data_size = data_size; +} + +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +void android_crash_detail_replace_name(crash_detail_t* crash_detail, const void* name, + size_t name_size) { + crash_detail->name = reinterpret_cast<const char*>(name); + crash_detail->name_size = name_size; +} diff --git a/libc/bionic/android_set_abort_message.cpp b/libc/bionic/android_set_abort_message.cpp index 53d75769d..05adf3e4c 100644 --- a/libc/bionic/android_set_abort_message.cpp +++ b/libc/bionic/android_set_abort_message.cpp @@ -29,7 +29,6 @@ #include <android/set_abort_message.h> #include <async_safe/log.h> -#include <bionic/set_abort_message_internal.h> #include <bits/stdatomic.h> #include <pthread.h> @@ -60,8 +59,6 @@ static_assert(offsetof(magic_abort_msg_t, msg) == 2 * sizeof(uint64_t), "The in-memory layout of magic_abort_msg_t is not consistent with what automated " "tools expect."); -static _Atomic(crash_detail_t*) free_head = nullptr; - [[clang::optnone]] static void fill_abort_message_magic(magic_abort_msg_t* new_magic_abort_message) { // 128-bit magic for the abort message. Chosen by fair dice roll. @@ -103,65 +100,3 @@ void android_set_abort_message(const char* msg) { strcpy(new_magic_abort_message->msg.msg, msg); __libc_shared_globals()->abort_msg = &new_magic_abort_message->msg; } - -__BIONIC_WEAK_FOR_NATIVE_BRIDGE -crash_detail_t* android_register_crash_detail(const void* name, size_t name_size, const void* data, - size_t data_size) { - auto populate_crash_detail = [&](crash_detail_t* result) { - result->name = reinterpret_cast<const char*>(name); - result->name_size = name_size; - result->data = reinterpret_cast<const char*>(data); - result->data_size = data_size; - }; - // This is a atomic fast-path for RAII use-cases where the app keeps creating and deleting - // crash details for short periods of time to capture detailed scopes. - if (crash_detail_t* head = atomic_load(&free_head)) { - while (head != nullptr && !atomic_compare_exchange_strong(&free_head, &head, head->prev_free)) { - // intentionally left blank. - } - if (head) { - head->prev_free = nullptr; - populate_crash_detail(head); - return head; - } - } - ScopedPthreadMutexLocker locker(&__libc_shared_globals()->crash_detail_page_lock); - struct crash_detail_page_t* prev = nullptr; - struct crash_detail_page_t* page = __libc_shared_globals()->crash_detail_page; - if (page != nullptr && page->used == kNumCrashDetails) { - prev = page; - page = nullptr; - } - if (page == nullptr) { - size_t size = sizeof(crash_detail_page_t); - void* map = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (map == MAP_FAILED) { - async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to allocate crash_detail_page: %m"); - return nullptr; - } - prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map, size, "crash details"); - page = reinterpret_cast<struct crash_detail_page_t*>(map); - page->prev = prev; - __libc_shared_globals()->crash_detail_page = page; - } - crash_detail_t* result = &page->crash_details[page->used]; - populate_crash_detail(result); - page->used++; - return result; -} - -__BIONIC_WEAK_FOR_NATIVE_BRIDGE -void android_unregister_crash_detail(crash_detail_t* crash_detail) { - if (crash_detail) { - if (crash_detail->prev_free) { - // removing already removed would mess up the free-list by creating a circle. - return; - } - crash_detail->data = nullptr; - crash_detail->name = nullptr; - crash_detail_t* prev = atomic_load(&free_head); - do { - crash_detail->prev_free = prev; - } while (!atomic_compare_exchange_strong(&free_head, &prev, crash_detail)); - } -} diff --git a/libc/include/android/crash_detail.h b/libc/include/android/crash_detail.h new file mode 100644 index 000000000..1fd082f54 --- /dev/null +++ b/libc/include/android/crash_detail.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +/** + * @file android/crash_detail.h + * @brief Attach extra information to android crashes. + */ + +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS + +typedef struct crash_detail_t crash_detail_t; + +/** + * Register a new buffer to get logged into tombstones for crashes. + * + * It will be added to both the tombstone proto in the crash_detail field, and + * in the tombstone text format. + * + * Tombstone proto definition: + * https://cs.android.com/android/platform/superproject/main/+/main:system/core/debuggerd/proto/tombstone.proto + * + * The lifetime of name and data has to be valid until the program crashes, or until + * android_crash_detail_unregister is called. + * + * Example usage: + * const char* stageName = "garbage_collection"; + * crash_detail_t* cd = android_crash_detail_register("stage", stageName, strlen(stageName)); + * do_garbage_collection(); + * android_crash_detail_unregister(cd); + * + * If this example crashes in do_garbage_collection, a line will show up in the textual representation of the tombstone: + * Extra crash detail: stage: 'garbage_collection' + * + * Introduced in API 35. + * + * \param name identifying name for this extra data. + * this should generally be a human-readable debug string, but we are treating + * it as arbitrary bytes because it could be corrupted by the crash. + * \param name_size number of bytes of the buffer pointed to by name + * \param data a buffer containing the extra detail bytes, if null the crash detail + * is disabled until android_crash_detail_replace_data replaces it with + * a non-null pointer. + * \param data_size number of bytes of the buffer pointed to by data + * + * \return a handle to the extra crash detail. + */ +crash_detail_t* _Nullable android_crash_detail_register( + const void* _Nonnull name, size_t name_size, const void* _Nullable data, size_t data_size) __INTRODUCED_IN(35); + +/** + * Unregister crash detail from being logged into tombstones. + * + * After this function returns, the lifetime of the objects crash_detail was + * constructed from no longer needs to be valid. + * + * Introduced in API 35. + * + * \param crash_detail the crash_detail that should be removed. + */ +void android_crash_detail_unregister(crash_detail_t* _Nonnull crash_detail) __INTRODUCED_IN(35); + +/** + * Replace data of crash detail. + * + * This is more efficient than using android_crash_detail_unregister followed by + * android_crash_detail_register. If you very frequently need to swap out the data, + * you can hold onto the crash_detail. + * + * Introduced in API 35. + * + * \param data the new buffer containing the extra detail bytes, or null to disable until + * android_crash_detail_replace_data is called again with non-null data. + * \param data_size the number of bytes of the buffer pointed to by data. + */ +void android_crash_detail_replace_data(crash_detail_t* _Nonnull crash_detail, const void* _Nullable data, size_t data_size) __INTRODUCED_IN(35); + +/** + * Replace name of crash detail. + * + * This is more efficient than using android_crash_detail_unregister followed by + * android_crash_detail_register. If you very frequently need to swap out the name, + * you can hold onto the crash_detail. + * + * Introduced in API 35. + * + * \param name identifying name for this extra data. + * \param name_size number of bytes of the buffer pointed to by name + */ +void android_crash_detail_replace_name(crash_detail_t* _Nonnull crash_detail, const void* _Nonnull name, size_t name_size) __INTRODUCED_IN(35); + +__END_DECLS diff --git a/libc/include/android/set_abort_message.h b/libc/include/android/set_abort_message.h index e92c6ec87..2525242ab 100644 --- a/libc/include/android/set_abort_message.h +++ b/libc/include/android/set_abort_message.h @@ -30,7 +30,7 @@ /** * @file android/set_abort_message.h - * @brief Attach extra information to android crashes. + * @brief The android_set_abort_message() function. */ #include <stddef.h> @@ -51,51 +51,4 @@ typedef struct crash_detail_t crash_detail_t; */ void android_set_abort_message(const char* _Nullable __msg); -/** - * Register a new buffer to get logged into tombstones for crashes. - * - * It will be added to both the tombstone proto in the crash_detail field, and - * in the tombstone text format. - * - * Tombstone proto definition: - * https://cs.android.com/android/platform/superproject/main/+/main:system/core/debuggerd/proto/tombstone.proto - * - * The lifetime of name and data has to be valid until the program crashes, or until - * android_unregister_crash_detail is called. - * - * Example usage: - * const char* stageName = "garbage_collection"; - * crash_detail_t* cd = android_register_crash_detail("stage", stageName, strlen(stageName)); - * do_garbage_collection(); - * android_unregister_crash_detail(cd); - * - * If this example crashes in do_garbage_collection, a line will show up in the textual representation of the tombstone: - * Extra crash detail: stage: 'garbage_collection' - * - * Introduced in API 35. - * - * \param name identifying name for this extra data. - * this should generally be a human-readable debug string, but we are treating - * it as arbitrary bytes because it could be corrupted by the crash. - * \param name_size number of bytes of the buffer pointed to by name - * \param data a buffer containing the extra detail bytes - * \param data_size number of bytes of the buffer pointed to by data - * - * \return a handle to the extra crash detail for use with android_unregister_crash_detail. - */ -crash_detail_t* _Nullable android_register_crash_detail( - const void* _Nonnull name, size_t name_size, const void* _Nonnull data, size_t data_size) __INTRODUCED_IN(35); - -/** - * Unregister crash detail from being logged into tombstones. - * - * After this function returns, the lifetime of the objects crash_detail was - * constructed from no longer needs to be valid. - * - * Introduced in API 35. - * - * \param crash_detail the crash_detail that should be removed. - */ -void android_unregister_crash_detail(crash_detail_t* _Nonnull crash_detail) __INTRODUCED_IN(35); - __END_DECLS diff --git a/libc/libc.map.txt b/libc/libc.map.txt index ecdb25c46..5e9763bef 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -1586,8 +1586,10 @@ LIBC_U { # introduced=UpsideDownCake LIBC_V { # introduced=VanillaIceCream global: - android_register_crash_detail; - android_unregister_crash_detail; + android_crash_detail_register; + android_crash_detail_unregister; + android_crash_detail_replace_name; + android_crash_detail_replace_data; epoll_pwait2; epoll_pwait2_64; localtime_rz; diff --git a/libc/platform/bionic/set_abort_message_internal.h b/libc/platform/bionic/crash_detail_internal.h index 4dff3acba..d8508a509 100644 --- a/libc/platform/bionic/set_abort_message_internal.h +++ b/libc/platform/bionic/crash_detail_internal.h @@ -28,7 +28,7 @@ #pragma once -#include <android/set_abort_message.h> +#include <android/crash_detail.h> #include <stddef.h> #include <sys/cdefs.h> |