[lib/debugger_utils] New function GetObjectName

Tested: New testcase added
Change-Id: I2d74ce03543539ce9fc0f997ce1f38b0bfec55af
diff --git a/garnet/lib/debugger_utils/util.h b/garnet/lib/debugger_utils/util.h
index 8aa6d2f..a701436 100644
--- a/garnet/lib/debugger_utils/util.h
+++ b/garnet/lib/debugger_utils/util.h
@@ -103,6 +103,12 @@
 // Convenience wrapper that takes an object.
 zx_koid_t GetRelatedKoid(const zx::object_base& object);
 
+// Return the ZX_PROP_NAME property of |handle|.
+// Returns "" if the object doesn't have a name (not all objects have names).
+std::string GetObjectName(zx_handle_t handle);
+// Convenience wrapper that takes an object.
+std::string GetObjectName(const zx::object_base& object);
+
 // Return the name of exception |type| as a C string.
 // Returns nullptr if |type| is invalid.
 // This does not take a |zx_excp_type_t| value because it also handles
diff --git a/garnet/lib/debugger_utils/util_zx.cc b/garnet/lib/debugger_utils/util_zx.cc
index 7c78d72..63825d4 100644
--- a/garnet/lib/debugger_utils/util_zx.cc
+++ b/garnet/lib/debugger_utils/util_zx.cc
@@ -47,6 +47,20 @@
   return GetRelatedKoid(object.get());
 }
 
+std::string GetObjectName(zx_handle_t handle) {
+  char name[ZX_MAX_NAME_LEN];
+  zx_status_t status = zx_object_get_property(handle, ZX_PROP_NAME,
+                                              name, sizeof(name));
+  if (status < 0) {
+    return "";
+  }
+  return name;
+}
+
+std::string GetObjectName(const zx::object_base& object) {
+  return GetObjectName(object.get());
+}
+
 std::string ZxErrorString(zx_status_t status) {
   return fxl::StringPrintf("%s(%d)", zx_status_get_string(status), status);
 }
diff --git a/garnet/lib/debugger_utils/util_zx_unittest.cc b/garnet/lib/debugger_utils/util_zx_unittest.cc
index 7154e9b..00312fb 100644
--- a/garnet/lib/debugger_utils/util_zx_unittest.cc
+++ b/garnet/lib/debugger_utils/util_zx_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <zx/event.h>
+#include <zx/socket.h>
 
 #include <lib/fdio/spawn.h>
 
@@ -47,5 +48,31 @@
   EXPECT_EQ(GetRelatedKoid(process.get()), GetKoid(job.get()));
 }
 
+TEST(UtilZx, GetObjectName) {
+  zx_handle_t self = zx_thread_self();
+  static const char name[] = "GetObjectNameTest";
+  ASSERT_EQ(zx_object_set_property(self, ZX_PROP_NAME, name, sizeof(name)),
+            ZX_OK);
+  ASSERT_STREQ(GetObjectName(self).c_str(), name);
+}
+
+TEST(UtilZx, GetNoNameObjectName) {
+  // Events don't have names, but also don't have properties,
+  // so we'll get ACCESS_DENIED.
+  zx::event event;
+  EXPECT_EQ(zx::event::create(0u, &event), ZX_OK);
+  static const char name[] = "GetNoNameObjectNameTest";
+  ASSERT_EQ(event.set_property(ZX_PROP_NAME, name, sizeof(name)),
+            ZX_ERR_ACCESS_DENIED);
+  ASSERT_STREQ(GetObjectName(event).c_str(), "");
+
+  // Sockets have properties but not names, so we'll get NOT_SUPPORTED.
+  zx::socket socket0, socket1;
+  EXPECT_EQ(zx::socket::create(0u, &socket0, &socket1), ZX_OK);
+  ASSERT_EQ(socket0.set_property(ZX_PROP_NAME, name, sizeof(name)),
+            ZX_ERR_NOT_SUPPORTED);
+  ASSERT_STREQ(GetObjectName(socket0).c_str(), "");
+}
+
 }  // namespace
 }  // namespace debugger_utils