114 lines
3.1 KiB
C++
114 lines
3.1 KiB
C++
#include <algorithm>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string.h>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <unistd.h>
|
|
#include <vector>
|
|
#include <editline/readline.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include "libedbg/error.hpp"
|
|
#include "libedbg/process.hpp"
|
|
|
|
namespace {
|
|
std::vector<std::string> split(const std::string_view str, char delimiter) {
|
|
std::vector<std::string> out{};
|
|
std::stringstream ss{std::string{str}};
|
|
std::string item;
|
|
|
|
while (std::getline(ss, item, delimiter)) {
|
|
out.push_back(item);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
bool is_prefix(std::string_view str, std::string_view of) {
|
|
if (str.size() < of.size()) {
|
|
return false;
|
|
}
|
|
return std::equal(str.begin(), str.end(), of.begin());
|
|
}
|
|
|
|
void print_stop_reason(const edbg::process& process, edbg::stop_reason reason) {
|
|
std::cout << "Process " << process.pid() << ' ';
|
|
|
|
switch (reason.reason) {
|
|
case edbg::process_state::exited:
|
|
std::cout << "exited with status " << static_cast<int>(reason.info);
|
|
break;
|
|
case edbg::process_state::terminated:
|
|
std::cout << "terminated with signal " << sigabbrev_np(reason.info);
|
|
case edbg::process_state::stopped:
|
|
std::cout << "stopped with signal " << sigabbrev_np(reason.info);
|
|
default: ;
|
|
}
|
|
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
void handle_command(const std::unique_ptr<edbg::process>& process, const std::string_view line) {
|
|
const auto args = split(line, ' ');
|
|
const auto& command = args[0];
|
|
if (is_prefix(command, "continue")) {
|
|
process->resume();
|
|
const auto reason = process->wait_on_signal();
|
|
print_stop_reason(*process, reason);
|
|
} else {
|
|
std::cerr << "Unknown command: " << command << "\n";
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<edbg::process> attach(const int argc, const char **argv) {
|
|
if (argc == 3 && argv[1] == std::string_view("-p")) {
|
|
const auto pid = static_cast<pid_t>(std::strtol(argv[2], nullptr, 10));
|
|
return edbg::process::attach(pid);
|
|
}
|
|
|
|
const char *program_path = argv[1];
|
|
return edbg::process::launch(program_path);
|
|
}
|
|
|
|
void main_loop(std::unique_ptr<edbg::process>& process) {
|
|
char *line = nullptr;
|
|
while ((line = readline("edbg> ")) != nullptr) {
|
|
std::string line_str;
|
|
|
|
if (line == std::string_view("")) {
|
|
free(line);
|
|
if (history_length > 0) {
|
|
line_str = history_list()[history_length - 1]->line;
|
|
}
|
|
} else {
|
|
line_str = line;
|
|
add_history(line_str.c_str());
|
|
free(line);
|
|
}
|
|
|
|
if (!line_str.empty()) {
|
|
try {
|
|
handle_command(process, line_str);
|
|
} catch (const edbg::error& err) {
|
|
std::cout << err.what() << "\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(const int argc, const char **argv) {
|
|
if (argc == 1) {
|
|
std::cerr << "No arguments given\n";
|
|
return -1;
|
|
}
|
|
|
|
try {
|
|
auto process = attach(argc, argv);
|
|
main_loop(process);
|
|
} catch (const edbg::error& err) {
|
|
std::cout << err.what() << "\n";
|
|
}
|
|
|
|
} |