blob: b2a1465050e1bd4c0da111403045627b6dffd5c4 [file] [log] [blame]
// 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