diff options
author | Josh Gao <jmgao@google.com> | 2018-08-06 18:26:42 -0700 |
---|---|---|
committer | Josh Gao <jmgao@google.com> | 2018-08-06 18:50:10 -0700 |
commit | ce841d91fb80f2f87aa43a82b8800704d324a99c (patch) | |
tree | fe6c760f5bd3a937570257c5059af97d9812d940 /debuggerd/libdebuggerd | |
parent | 9da1f51c102e18ef88b7f244b2c871054e1dd9c8 (diff) |
libdebuggerd: extract and print the fdsan table.
This commit only prints the raw value of the owner tag, pretty-printing
will come in a follow-up commit.
Test: debuggerd `pidof adbd`
Test: static_crasher fdsan_file + manual inspection of tombstone
Change-Id: Idb7375a12e410d5b51e6fcb6885d4beb20bccd0e
Diffstat (limited to 'debuggerd/libdebuggerd')
-rw-r--r-- | debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h | 26 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/open_files_list.cpp | 79 | ||||
-rw-r--r-- | debuggerd/libdebuggerd/test/open_files_list_test.cpp | 6 |
3 files changed, 94 insertions, 17 deletions
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h b/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h index 4727ca4d7..d47f2ddf6 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/open_files_list.h @@ -14,23 +14,31 @@ * limitations under the License. */ -#ifndef _DEBUGGERD_OPEN_FILES_LIST_H -#define _DEBUGGERD_OPEN_FILES_LIST_H +#pragma once +#include <stdint.h> #include <sys/types.h> +#include <map> +#include <optional> #include <string> #include <utility> -#include <vector> #include "utility.h" -typedef std::vector<std::pair<int, std::string>> OpenFilesList; +struct FDInfo { + std::optional<std::string> path; + std::optional<uint64_t> fdsan_owner; +}; -/* Populates the given list with open files for the given process. */ -void populate_open_files_list(pid_t pid, OpenFilesList* list); +using OpenFilesList = std::map<int, FDInfo>; -/* Dumps the open files list to the log. */ -void dump_open_files_list(log_t* log, const OpenFilesList& files, const char* prefix); +// Populates the given list with open files for the given process. +void populate_open_files_list(OpenFilesList* list, pid_t pid); + +// Populates the given list with the target process's fdsan table. +void populate_fdsan_table(OpenFilesList* list, std::shared_ptr<unwindstack::Memory> memory, + uint64_t fdsan_table_address); -#endif // _DEBUGGERD_OPEN_FILES_LIST_H +// Dumps the open files list to the log. +void dump_open_files_list(log_t* log, const OpenFilesList& files, const char* prefix); diff --git a/debuggerd/libdebuggerd/open_files_list.cpp b/debuggerd/libdebuggerd/open_files_list.cpp index b12703e14..1fdf2369a 100644 --- a/debuggerd/libdebuggerd/open_files_list.cpp +++ b/debuggerd/libdebuggerd/open_files_list.cpp @@ -32,10 +32,12 @@ #include <android-base/file.h> #include <log/log.h> +#include <unwindstack/Memory.h> #include "libdebuggerd/utility.h" +#include "private/bionic_fdsan.h" -void populate_open_files_list(pid_t pid, OpenFilesList* list) { +void populate_open_files_list(OpenFilesList* list, pid_t pid) { std::string fd_dir_name = "/proc/" + std::to_string(pid) + "/fd"; std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(fd_dir_name.c_str()), closedir); if (dir == nullptr) { @@ -53,17 +55,84 @@ void populate_open_files_list(pid_t pid, OpenFilesList* list) { std::string path = fd_dir_name + "/" + std::string(de->d_name); std::string target; if (android::base::Readlink(path, &target)) { - list->emplace_back(fd, target); + (*list)[fd].path = target; } else { + (*list)[fd].path = "???"; ALOGE("failed to readlink %s: %s", path.c_str(), strerror(errno)); - list->emplace_back(fd, "???"); } } } +void populate_fdsan_table(OpenFilesList* list, std::shared_ptr<unwindstack::Memory> memory, + uint64_t fdsan_table_address) { + constexpr size_t inline_fds = sizeof(FdTable::entries) / sizeof(*FdTable::entries); + static_assert(inline_fds == 128); + size_t entry_offset = offsetof(FdTable, entries); + for (size_t i = 0; i < inline_fds; ++i) { + uint64_t address = fdsan_table_address + entry_offset + sizeof(FdEntry) * i; + FdEntry entry; + if (!memory->Read(address, &entry, sizeof(entry))) { + ALOGE("failed to read fdsan table entry %zu: %s", i, strerror(errno)); + return; + } + ALOGE("fd %zu = %#" PRIx64, i, entry.close_tag.load()); + if (entry.close_tag) { + (*list)[i].fdsan_owner = entry.close_tag.load(); + } + } + + size_t overflow_offset = offsetof(FdTable, overflow); + uintptr_t overflow = 0; + if (!memory->Read(fdsan_table_address + overflow_offset, &overflow, sizeof(overflow))) { + ALOGE("failed to read fdsan table overflow pointer: %s", strerror(errno)); + return; + } + + if (!overflow) { + return; + } + + size_t overflow_length; + if (!memory->Read(overflow, &overflow_length, sizeof(overflow_length))) { + ALOGE("failed to read fdsan overflow table length: %s", strerror(errno)); + return; + } + + if (overflow_length > 131072) { + ALOGE("unreasonable large fdsan overflow table size %zu, bailing out", overflow_length); + return; + } + + for (size_t i = 0; i < overflow_length; ++i) { + int fd = i + inline_fds; + uint64_t address = overflow + offsetof(FdTableOverflow, entries) + i * sizeof(FdEntry); + FdEntry entry; + if (!memory->Read(address, &entry, sizeof(entry))) { + ALOGE("failed to read fdsan overflow entry for fd %d: %s", fd, strerror(errno)); + return; + } + if (entry.close_tag) { + (*list)[fd].fdsan_owner = entry.close_tag; + } + } + return; +} + void dump_open_files_list(log_t* log, const OpenFilesList& files, const char* prefix) { - for (auto& file : files) { - _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s\n", prefix, file.first, file.second.c_str()); + for (auto& [fd, entry] : files) { + const std::optional<std::string>& path = entry.path; + const std::optional<uint64_t>& fdsan_owner = entry.fdsan_owner; + if (path && fdsan_owner) { + _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s (owned by %#" PRIx64 ")\n", prefix, fd, + path->c_str(), *fdsan_owner); + } else if (path && !fdsan_owner) { + _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s (unowned)\n", prefix, fd, path->c_str()); + } else if (!path && fdsan_owner) { + _LOG(log, logtype::OPEN_FILES, "%sfd %i: <MISSING> (owned by %#" PRIx64 ")\n", prefix, fd, + *fdsan_owner); + } else { + ALOGE("OpenFilesList contains an entry (fd %d) with no path or owner", fd); + } } } diff --git a/debuggerd/libdebuggerd/test/open_files_list_test.cpp b/debuggerd/libdebuggerd/test/open_files_list_test.cpp index acac72c22..d7036fd39 100644 --- a/debuggerd/libdebuggerd/test/open_files_list_test.cpp +++ b/debuggerd/libdebuggerd/test/open_files_list_test.cpp @@ -34,13 +34,13 @@ TEST(OpenFilesListTest, BasicTest) { // Get the list of open files for this process. OpenFilesList list; - populate_open_files_list(getpid(), &list); + populate_open_files_list(&list, getpid()); // Verify our open file is in the list. bool found = false; - for (auto& file : list) { + for (auto& file : list) { if (file.first == tf.fd) { - EXPECT_EQ(file.second, std::string(tf.path)); + EXPECT_EQ(file.second.path.value_or(""), std::string(tf.path)); found = true; break; } |