blob: 024cbda34bf90bdb9d8674b90715bc5cd978a820 [file] [log] [blame]
// Copyright 2019 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 <signal.h>
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <optional>
#include <string>
#include <thread>
#include <vector>
#include "tools/fidlcat/command_line_options.h"
#include "tools/fidlcat/lib/interception_workflow.h"
// TODO(fidlcat): Look into this. Removing the hack that led to this (in
// debug_ipc/helper/message_loop.h) seems to work, except it breaks SDK builds
// on CQ in a way I can't repro locally.
#undef __TA_REQUIRES
#include "lib/fidl/cpp/message.h"
#include "src/developer/debug/zxdb/common/inet_util.h"
#include "tools/fidlcat/lib/library_loader.h"
#include "tools/fidlcat/lib/message_decoder.h"
#include "tools/fidlcat/lib/syscall_decoder_dispatcher.h"
namespace fidlcat {
static bool called_onexit_once_ = false;
static std::atomic<InterceptionWorkflow*> workflow_;
static void OnExit(int /*signum*/, siginfo_t* /*info*/, void* /*ptr*/) {
if (called_onexit_once_) {
// Exit immediately.
#if defined(__APPLE__)
_Exit(1);
#else
_exit(1);
#endif
} else {
// Maybe detach cleanly here, if we can.
FXL_LOG(INFO) << "Shutting down...";
called_onexit_once_ = true;
workflow_.load()->Shutdown();
}
}
void CatchSigterm() {
static struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = OnExit;
action.sa_flags = SA_SIGINFO;
sigaction(SIGINT, &action, nullptr);
}
// Add the startup actions to the loop: connect, attach to pid, set breakpoints.
void EnqueueStartup(InterceptionWorkflow* workflow, const CommandLineOptions& options,
const std::vector<std::string>& params) {
std::vector<uint64_t> process_koids;
if (!options.remote_pid.empty()) {
for (const std::string& pid_str : options.remote_pid) {
uint64_t process_koid = strtoull(pid_str.c_str(), nullptr, kDecimalBase);
// There is no process 0, and if there were, we probably wouldn't be able to
// talk with it.
if (process_koid == 0) {
fprintf(stderr, "Invalid pid %s\n", pid_str.c_str());
exit(1);
}
process_koids.push_back(process_koid);
}
}
std::string host;
uint16_t port;
zxdb::Err parse_err = zxdb::ParseHostPort(*(options.connect), &host, &port);
if (!parse_err.ok()) {
FXL_LOG(FATAL) << "Could not parse host/port pair: " << parse_err.msg();
}
auto attach = [workflow, process_koids, remote_name = options.remote_name,
params](const zxdb::Err& err) {
if (!err.ok()) {
FXL_LOG(FATAL) << "Unable to connect: " << err.msg();
return;
}
FXL_LOG(INFO) << "Connected!";
if (!process_koids.empty()) {
workflow->Attach(process_koids);
}
if (remote_name.empty()) {
if (std::find(params.begin(), params.end(), "run") != params.end()) {
zxdb::Target* target = workflow->GetNewTarget();
workflow->AddObserver(target);
workflow->Launch(target, params);
}
} else {
zxdb::Target* target = workflow->GetNewTarget();
workflow->AddObserver(target);
if (std::find(params.begin(), params.end(), "run") != params.end()) {
workflow->Launch(target, params);
}
workflow->Filter(remote_name);
}
};
auto connect = [workflow, attach = std::move(attach), host, port]() {
FXL_LOG(INFO) << "Connecting to port " << port << " on " << host << "...";
workflow->Connect(host, port, attach);
};
debug_ipc::MessageLoop::Current()->PostTask(FROM_HERE, connect);
}
int ConsoleMain(int argc, const char* argv[]) {
CommandLineOptions options;
DecodeOptions decode_options;
DisplayOptions display_options;
std::vector<std::string> params;
cmdline::Status status =
ParseCommandLine(argc, argv, &options, &decode_options, &display_options, &params);
if (status.has_error()) {
fprintf(stderr, "%s\n", status.error_message().c_str());
return 1;
}
std::vector<std::unique_ptr<std::istream>> paths;
std::vector<std::string> bad_paths;
ExpandFidlPathsFromOptions(options.fidl_ir_paths, paths, bad_paths);
if (paths.empty()) {
std::string error = "No FIDL IR paths provided.";
if (!bad_paths.empty()) {
error.append(" File(s) not found: [ ");
for (auto& s : bad_paths) {
error.append(s);
error.append(" ");
}
error.append("]");
}
FXL_LOG(INFO) << error;
}
fidlcat::LibraryReadError loader_err;
LibraryLoader loader(&paths, &loader_err);
if (loader_err.value != fidlcat::LibraryReadError::kOk) {
FXL_LOG(ERROR) << "Failed to read libraries";
return 1;
}
InterceptionWorkflow workflow;
workflow.Initialize(options.symbol_paths, options.symbol_repo_paths,
std::make_unique<SyscallDisplayDispatcher>(&loader, decode_options,
display_options, std::cout));
EnqueueStartup(&workflow, options, params);
// TODO(fidlcat): When the attached koid terminates normally, we should exit and call
// QuitNow() on the MessageLoop.
workflow_.store(&workflow);
CatchSigterm();
InterceptionWorkflow::Go();
return 0;
}
} // namespace fidlcat
int main(int argc, const char* argv[]) { fidlcat::ConsoleMain(argc, argv); }