From 1febd59f830d0c5ee240b73c7fd376c18f76f754 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 17 Aug 2019 11:35:09 +0200 Subject: [PATCH] LibCore+rpcdump: Publish CObject graph to on-demand RPC socket All programs that have a CEventLoop now allow local socket connections via /tmp/rpc.PID and will dump a serialized JSON array of all the live CObjects in the program onto connecting sockets. Also added a small /bin/rpcdump tool that connects to an RPC socket and produces a raw dump of the JSON that comes out. --- Libraries/LibCore/CEventLoop.cpp | 31 +++++++++++++++++++++++ Libraries/LibCore/CEventLoop.h | 5 +++- Userland/rpcdump.cpp | 42 ++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 Userland/rpcdump.cpp diff --git a/Libraries/LibCore/CEventLoop.cpp b/Libraries/LibCore/CEventLoop.cpp index 2e50891b158..26adf6fd772 100644 --- a/Libraries/LibCore/CEventLoop.cpp +++ b/Libraries/LibCore/CEventLoop.cpp @@ -1,6 +1,10 @@ +#include +#include +#include #include #include #include +#include #include #include #include @@ -25,6 +29,7 @@ HashMap>* CEventLoop::s_timers; HashTable* CEventLoop::s_notifiers; int CEventLoop::s_next_timer_id = 1; int CEventLoop::s_wake_pipe_fds[2]; +CLocalServer CEventLoop::s_rpc_server; CEventLoop::CEventLoop() { @@ -39,6 +44,32 @@ CEventLoop::CEventLoop() int rc = pipe2(s_wake_pipe_fds, O_CLOEXEC); ASSERT(rc == 0); s_event_loop_stack->append(this); + + + auto rpc_path = String::format("/tmp/rpc.%d", getpid()); + rc = unlink(rpc_path.characters()); + if (rc < 0 && errno != ENOENT) { + perror("unlink"); + ASSERT_NOT_REACHED(); + } + bool listening = s_rpc_server.listen(rpc_path); + ASSERT(listening); + + s_rpc_server.on_ready_to_accept = [&] { + auto* client = s_rpc_server.accept(); + ASSERT(client); + JsonArray objects; + for (auto& object : CObject::all_objects()) { + JsonObject json_object; + json_object.set("class_name", object.class_name()); + json_object.set("address", String::format("%p", &object)); + json_object.set("name", object.name()); + json_object.set("parent", String::format("%p", object.parent())); + objects.append(move(json_object)); + } + client->write(objects.to_string()); + client->delete_later(); + }; } #ifdef CEVENTLOOP_DEBUG diff --git a/Libraries/LibCore/CEventLoop.h b/Libraries/LibCore/CEventLoop.h index 41cb35bc364..aa7777b7686 100644 --- a/Libraries/LibCore/CEventLoop.h +++ b/Libraries/LibCore/CEventLoop.h @@ -5,8 +5,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -85,4 +86,6 @@ private: static int s_next_timer_id; static HashTable* s_notifiers; + + static CLocalServer s_rpc_server; }; diff --git a/Userland/rpcdump.cpp b/Userland/rpcdump.cpp new file mode 100644 index 00000000000..0b421a7d5b0 --- /dev/null +++ b/Userland/rpcdump.cpp @@ -0,0 +1,42 @@ +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc != 2) { + printf("usage: %s \n", argv[0]); + return 0; + } + + CEventLoop loop; + + int pid = atoi(argv[1]); + + CLocalSocket socket; + auto success = socket.connect(CSocketAddress::local(String::format("/tmp/rpc.%d", pid))); + if (!success) { + fprintf(stderr, "Couldn't connect to PID %d\n", pid); + return 1; + } + + socket.on_connected = [&] { + dbg() << "Connected to PID " << pid; + }; + + socket.on_ready_to_read = [&] { + if (socket.eof()) { + dbg() << "Disconnected from PID " << pid; + loop.quit(0); + return; + } + + auto data = socket.read_all(); + + for (int i = 0; i < data.size(); ++i) + putchar(data[i]); + printf("\n"); + }; + + return loop.exec(); +}