fdsan: expose functions to get and interpret tags.

Make it easier to write tests in users of fdsan by exposing functions
to allow users to get and interpret the tags.

Test: bionic_unit_tests
Change-Id: Iafa9bcaeb5e4db230f3dfec6f483274f34602694
diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp
index 67b3a62..d877172 100644
--- a/libc/bionic/fdsan.cpp
+++ b/libc/bionic/fdsan.cpp
@@ -218,7 +218,7 @@
   return result;
 }
 
-static const char* __tag_to_type(uint64_t tag) {
+const char* android_fdsan_get_tag_type(uint64_t tag) {
   uint64_t type = tag >> 56;
   switch (type) {
     case ANDROID_FDSAN_OWNER_TYPE_FILE:
@@ -253,7 +253,7 @@
   }
 }
 
-static uint64_t __tag_to_owner(uint64_t tag) {
+uint64_t android_fdsan_get_tag_value(uint64_t tag) {
   // Lop off the most significant byte and sign extend.
   return static_cast<uint64_t>(static_cast<int64_t>(tag << 8) >> 8);
 }
@@ -266,10 +266,10 @@
 
   uint64_t tag = expected_tag;
   if (!atomic_compare_exchange_strong(&fde->close_tag, &tag, 0)) {
-    const char* expected_type = __tag_to_type(expected_tag);
-    uint64_t expected_owner = __tag_to_owner(expected_tag);
-    const char* actual_type = __tag_to_type(tag);
-    uint64_t actual_owner = __tag_to_owner(tag);
+    const char* expected_type = android_fdsan_get_tag_type(expected_tag);
+    uint64_t expected_owner = android_fdsan_get_tag_value(expected_tag);
+    const char* actual_type = android_fdsan_get_tag_type(tag);
+    uint64_t actual_owner = android_fdsan_get_tag_value(tag);
     if (expected_tag && tag) {
       fdsan_error(
           "attempted to close file descriptor %d, "
@@ -299,6 +299,14 @@
   return rc;
 }
 
+uint64_t android_fdsan_get_owner_tag(int fd) {
+  FdEntry* fde = GetFdEntry(fd);
+  if (!fde) {
+    return 0;
+  }
+  return fde->close_tag;
+}
+
 void android_fdsan_exchange_owner_tag(int fd, uint64_t expected_tag, uint64_t new_tag) {
   FdEntry* fde = GetFdEntry(fd);
   if (!fde) {
@@ -311,18 +319,18 @@
       fdsan_error(
           "failed to exchange ownership of file descriptor: fd %d is "
           "owned by %s 0x%" PRIx64 ", was expected to be owned by %s 0x%" PRIx64,
-          fd, __tag_to_type(tag), __tag_to_owner(tag), __tag_to_type(expected_tag),
-          __tag_to_owner(expected_tag));
+          fd, android_fdsan_get_tag_type(tag), android_fdsan_get_tag_value(tag),
+          android_fdsan_get_tag_type(expected_tag), android_fdsan_get_tag_value(expected_tag));
     } else if (expected_tag && !tag) {
       fdsan_error(
           "failed to exchange ownership of file descriptor: fd %d is "
           "unowned, was expected to be owned by %s 0x%" PRIx64,
-          fd, __tag_to_type(expected_tag), __tag_to_owner(expected_tag));
+          fd, android_fdsan_get_tag_type(expected_tag), android_fdsan_get_tag_value(expected_tag));
     } else if (!expected_tag && tag) {
       fdsan_error(
           "failed to exchange ownership of file descriptor: fd %d is "
           "owned by %s 0x%" PRIx64 ", was expected to be unowned",
-          fd, __tag_to_type(tag), __tag_to_owner(tag));
+          fd, android_fdsan_get_tag_type(tag), android_fdsan_get_tag_value(tag));
     } else if (!expected_tag && !tag) {
       // This should never happen: our CAS failed, but expected == actual?
       async_safe_fatal(
diff --git a/libc/include/android/fdsan.h b/libc/include/android/fdsan.h
index 11f33fd..9c58e27 100644
--- a/libc/include/android/fdsan.h
+++ b/libc/include/android/fdsan.h
@@ -132,6 +132,25 @@
  */
 int android_fdsan_close_with_tag(int fd, uint64_t tag) __INTRODUCED_IN_FUTURE __attribute__((__weak__));
 
+/*
+ * Get a file descriptor's current owner tag.
+ *
+ * Returns 0 for untagged and invalid file descriptors.
+ */
+uint64_t android_fdsan_get_owner_tag(int fd);
+
+/*
+ * Get an owner tag's string representation.
+ *
+ * The return value points to memory with static lifetime, do not attempt to modify it.
+ */
+const char* android_fdsan_get_tag_type(uint64_t tag);
+
+/*
+ * Get an owner tag's value, with the type masked off.
+ */
+uint64_t android_fdsan_get_tag_value(uint64_t tag);
+
 enum android_fdsan_error_level {
   // No errors.
   ANDROID_FDSAN_ERROR_LEVEL_DISABLED,
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 6d39812..f1eec3c 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1426,6 +1426,9 @@
     android_fdsan_close_with_tag;
     android_fdsan_create_owner_tag;
     android_fdsan_exchange_owner_tag;
+    android_fdsan_get_owner_tag;
+    android_fdsan_get_tag_type;
+    android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
     timespec_get;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 1cf48b1..4d538cd 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1347,6 +1347,9 @@
     android_fdsan_close_with_tag;
     android_fdsan_create_owner_tag;
     android_fdsan_exchange_owner_tag;
+    android_fdsan_get_owner_tag;
+    android_fdsan_get_tag_type;
+    android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
     timespec_get;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 135206e..0f5abc0 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1451,6 +1451,9 @@
     android_fdsan_close_with_tag;
     android_fdsan_create_owner_tag;
     android_fdsan_exchange_owner_tag;
+    android_fdsan_get_owner_tag;
+    android_fdsan_get_tag_type;
+    android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
     timespec_get;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index a330a45..f14f731 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1410,6 +1410,9 @@
     android_fdsan_close_with_tag;
     android_fdsan_create_owner_tag;
     android_fdsan_exchange_owner_tag;
+    android_fdsan_get_owner_tag;
+    android_fdsan_get_tag_type;
+    android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
     timespec_get;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 1cf48b1..4d538cd 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1347,6 +1347,9 @@
     android_fdsan_close_with_tag;
     android_fdsan_create_owner_tag;
     android_fdsan_exchange_owner_tag;
+    android_fdsan_get_owner_tag;
+    android_fdsan_get_tag_type;
+    android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
     timespec_get;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 7a2fe9a..d44001e 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1408,6 +1408,9 @@
     android_fdsan_close_with_tag;
     android_fdsan_create_owner_tag;
     android_fdsan_exchange_owner_tag;
+    android_fdsan_get_owner_tag;
+    android_fdsan_get_tag_type;
+    android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
     timespec_get;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 1cf48b1..4d538cd 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1347,6 +1347,9 @@
     android_fdsan_close_with_tag;
     android_fdsan_create_owner_tag;
     android_fdsan_exchange_owner_tag;
+    android_fdsan_get_owner_tag;
+    android_fdsan_get_tag_type;
+    android_fdsan_get_tag_value;
     android_fdsan_get_error_level;
     android_fdsan_set_error_level;
     timespec_get;