Add a utility to print out contents of queue memory

This is helpful when debugging corruption of the queue, or other low
level debugging of queue state.

Change-Id: Id3ae06e6e131238d9f227b431d4cece8368322e8
diff --git a/aos/ipc_lib/BUILD b/aos/ipc_lib/BUILD
index 1916e7a..5e14abc 100644
--- a/aos/ipc_lib/BUILD
+++ b/aos/ipc_lib/BUILD
@@ -288,3 +288,14 @@
         "@com_github_gflags_gflags//:gflags",
     ],
 )
+
+cc_binary(
+    name = "print_lockless_queue_memory",
+    visibility = ["//visibility:public"],
+    srcs = [
+        "print_lockless_queue_memory.cc",
+    ],
+    deps = [
+        ":lockless_queue",
+    ],
+)
diff --git a/aos/ipc_lib/lockless_queue.cc b/aos/ipc_lib/lockless_queue.cc
index 030054a..a450560 100644
--- a/aos/ipc_lib/lockless_queue.cc
+++ b/aos/ipc_lib/lockless_queue.cc
@@ -12,8 +12,12 @@
 #include "aos/ipc_lib/lockless_queue_memory.h"
 #include "aos/realtime.h"
 #include "aos/util/compiler_memory_barrier.h"
+#include "gflags/gflags.h"
 #include "glog/logging.h"
 
+DEFINE_bool(dump_lockless_queue_data, false,
+            "If true, print the data out when dumping the queue.");
+
 namespace aos {
 namespace ipc_lib {
 namespace {
@@ -946,28 +950,51 @@
               << ::std::endl;
   for (size_t i = 0; i < memory->num_messages(); ++i) {
     Message *m = memory->GetMessage(Index(i, i));
-    ::std::cout << "    [" << i << "] -> Message {" << ::std::endl;
+    ::std::cout << "    [" << i << "] -> Message 0x" << std::hex
+                << (reinterpret_cast<uintptr_t>(
+                        memory->GetMessage(Index(i, i))) -
+                    reinterpret_cast<uintptr_t>(memory))
+                << std::dec << " {" << ::std::endl;
     ::std::cout << "      Header {" << ::std::endl;
     ::std::cout << "        AtomicQueueIndex queue_index = "
                 << m->header.queue_index.Load(queue_size).DebugString()
                 << ::std::endl;
+    ::std::cout << "        monotonic_clock::time_point monotonic_sent_time = "
+                << m->header.monotonic_sent_time << " 0x" << std::hex
+                << m->header.monotonic_sent_time.time_since_epoch().count()
+                << std::dec << ::std::endl;
+    ::std::cout << "        realtime_clock::time_point realtime_sent_time = "
+                << m->header.realtime_sent_time << " 0x" << std::hex
+                << m->header.realtime_sent_time.time_since_epoch().count()
+                << std::dec << ::std::endl;
+    ::std::cout
+        << "        monotonic_clock::time_point monotonic_remote_time = "
+        << m->header.monotonic_remote_time << " 0x" << std::hex
+        << m->header.monotonic_remote_time.time_since_epoch().count()
+        << std::dec << ::std::endl;
+    ::std::cout << "        realtime_clock::time_point realtime_remote_time = "
+                << m->header.realtime_remote_time << " 0x" << std::hex
+                << m->header.realtime_remote_time.time_since_epoch().count()
+                << std::dec << ::std::endl;
     ::std::cout << "        size_t length = " << m->header.length
                 << ::std::endl;
     ::std::cout << "      }" << ::std::endl;
     ::std::cout << "      data: {";
 
-    const char *const m_data = m->data(memory->message_data_size());
-    for (size_t j = 0; j < m->header.length; ++j) {
-      char data = m_data[j];
-      if (j != 0) {
-        ::std::cout << " ";
-      }
-      if (::std::isprint(data)) {
-        ::std::cout << ::std::setfill(' ') << ::std::setw(2) << ::std::hex
-                    << data;
-      } else {
-        ::std::cout << "0x" << ::std::setfill('0') << ::std::setw(2)
-                    << ::std::hex << (static_cast<unsigned>(data) & 0xff);
+    if (FLAGS_dump_lockless_queue_data) {
+      const char *const m_data = m->data(memory->message_data_size());
+      for (size_t j = 0; j < m->header.length; ++j) {
+        char data = m_data[j];
+        if (j != 0) {
+          ::std::cout << " ";
+        }
+        if (::std::isprint(data)) {
+          ::std::cout << ::std::setfill(' ') << ::std::setw(2) << ::std::hex
+                      << data;
+        } else {
+          ::std::cout << "0x" << ::std::setfill('0') << ::std::setw(2)
+                      << ::std::hex << (static_cast<unsigned>(data) & 0xff);
+        }
       }
     }
     ::std::cout << ::std::setfill(' ') << ::std::dec << "}" << ::std::endl;
diff --git a/aos/ipc_lib/print_lockless_queue_memory.cc b/aos/ipc_lib/print_lockless_queue_memory.cc
new file mode 100644
index 0000000..6974d65
--- /dev/null
+++ b/aos/ipc_lib/print_lockless_queue_memory.cc
@@ -0,0 +1,29 @@
+#include "aos/ipc_lib/lockless_queue.h"
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+int main(int argc, char **argv) {
+  CHECK_EQ(argc, 2);
+  const char *path = argv[1];
+
+  struct stat st;
+  PCHECK(lstat(path, &st) == 0);
+  CHECK_NE(st.st_size, 0);
+  const size_t size = st.st_size;
+
+  // File already exists.
+  int fd = open(path, O_RDWR, O_CLOEXEC);
+  PCHECK(fd != -1) << ": Failed to open " << path;
+
+  void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  PCHECK(data != MAP_FAILED);
+  PCHECK(close(fd) == 0);
+
+  aos::ipc_lib::PrintLocklessQueueMemory(
+      reinterpret_cast<aos::ipc_lib::LocklessQueueMemory *>(data));
+
+  PCHECK(munmap(data, size) == 0);
+}