| // Copyright 2023 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/debug/zxdb/local_agent.h" |
| |
| #include <fcntl.h> |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include <thread> |
| |
| #include "src/developer/debug/debug_agent/debug_agent.h" |
| #include "src/developer/debug/debug_agent/linux_system_interface.h" |
| #include "src/developer/debug/debug_agent/remote_api_adapter.h" |
| #include "src/developer/debug/shared/buffered_bidi_pipe.h" |
| #include "src/developer/debug/shared/logging/logging.h" |
| #include "src/developer/debug/shared/platform_message_loop.h" |
| |
| namespace zxdb { |
| |
| int RunLocalAgent(fbl::unique_fd read_pipe, fbl::unique_fd write_pipe) { |
| // Uncomment to enable debugging output for the local debug_agent. Currently there is not |
| // configurable from the command line, as the --debug mode option only applies to the frontend |
| // code. |
| #if 0 |
| printf("Running local agent on PID %d\n", getpid()); |
| debug::SetLogCategories({debug::LogCategory::kAll}); |
| debug::SetDebugLogging(true); |
| #endif |
| |
| debug::PlatformMessageLoop message_loop; |
| std::string init_error_message; |
| if (!message_loop.Init(&init_error_message)) { |
| FX_LOGS(ERROR) << init_error_message; |
| return 1; |
| } |
| |
| // The scope ensures the objects are destroyed before calling Cleanup on the MessageLoop. |
| { |
| // The debug agent is independent of whether it's connected or not. |
| // DebugAgent::Disconnect is called by ~SocketConnection is called by ~SocketServer, so the |
| // debug agent must be destructed after the SocketServer. |
| debug_agent::DebugAgent debug_agent(std::make_unique<debug_agent::LinuxSystemInterface>()); |
| auto buffer = |
| std::make_unique<debug::BufferedBidiPipe>(std::move(read_pipe), std::move(write_pipe)); |
| |
| debug_agent.TakeAndConnectRemoteAPIStream(std::move(buffer)); |
| message_loop.Run(); |
| } |
| |
| message_loop.Cleanup(); |
| return 0; |
| } |
| |
| LocalAgentResult ForkLocalAgent() { |
| // Two pipes, one for each direction to communicate with the agent. |
| const char kPipeError[] = "Can't create pipe to agent process.\n"; |
| int client_to_agent[2] = {0, 0}; |
| if (pipe2(client_to_agent, O_NONBLOCK) == -1) { |
| fprintf(stderr, kPipeError); |
| return LocalAgentResult(LocalAgentResult::kFailed, 1); |
| } |
| |
| int agent_to_client[2] = {0, 0}; |
| if (pipe2(agent_to_client, O_NONBLOCK) == -1) { |
| fprintf(stderr, kPipeError); |
| return LocalAgentResult(LocalAgentResult::kFailed, 1); |
| } |
| |
| pid_t child_pid = fork(); |
| if (child_pid == -1) { |
| fprintf(stderr, "Can't fork agent process\n"); |
| return LocalAgentResult(LocalAgentResult::kFailed, 1); |
| } else if (child_pid == 0) { |
| // Run the debug agent. |
| |
| // Close the handles the frontend uses. |
| close(client_to_agent[1]); |
| close(agent_to_client[0]); |
| int exit_code = |
| RunLocalAgent(fbl::unique_fd(client_to_agent[0]), fbl::unique_fd(agent_to_client[1])); |
| return LocalAgentResult(LocalAgentResult::kInForked, exit_code); |
| } |
| |
| // This is the zxdb frontend process. Close the handles the agent uses. |
| close(client_to_agent[0]); |
| close(agent_to_client[1]); |
| |
| // The other end gets returned as the Bidi pipe. |
| auto bidi_pipe = std::make_unique<debug::BufferedBidiPipe>(fbl::unique_fd(agent_to_client[0]), |
| fbl::unique_fd(client_to_agent[1])); |
| |
| return LocalAgentResult(child_pid, std::move(bidi_pipe)); |
| } |
| |
| } // namespace zxdb |