6#include <clues/logger.hxx>
7#include <clues/sysnrs/generic.hxx>
8#include <clues/utils.hxx>
11#include <clues/errnodb.hxx>
12#include <clues/Tracee.hxx>
15#include <cosmos/error/ApiError.hxx>
16#include <cosmos/error/RuntimeError.hxx>
17#include <cosmos/formatting.hxx>
18#include <cosmos/fs/DirStream.hxx>
19#include <cosmos/fs/File.hxx>
20#include <cosmos/fs/filesystem.hxx>
21#include <cosmos/io/ILogger.hxx>
22#include <cosmos/io/StreamAdaptor.hxx>
23#include <cosmos/proc/process.hxx>
24#include <cosmos/string.hxx>
25#include <cosmos/utils.hxx>
30 const auto num = cosmos::to_integral(err);
31 if (num < 0 ||
static_cast<size_t>(num) >= ERRNO_NAMES.size())
34 return ERRNO_NAMES[num];
39 case KernelErrno::RESTART_SYS:
return "RESTART_SYS";
40 case KernelErrno::RESTART_NOINTR:
return "RESTART_NOINTR";
41 case KernelErrno::RESTART_NOHAND:
return "RESTART_NOHAND";
42 case KernelErrno::RESTART_RESTARTBLOCK:
return "RESTART_RESTARTBLOCK";
43 default:
return "?INVALID?";
48 using Event = cosmos::ptrace::Event;
50 case Event::VFORK:
return "VFORK";
51 case Event::FORK:
return "FORK";
52 case Event::CLONE:
return "CLONE";
53 case Event::VFORK_DONE:
return "VFORK_DONE";
54 case Event::EXEC:
return "EXEC";
55 case Event::EXIT:
return "EXIT";
56 case Event::STOP:
return "STOP";
57 case Event::SECCOMP:
return "SECCOMP";
58 default:
return "??? unknown ???";
63 std::set<cosmos::FileNum> ret;
66 cosmos::DirStream dir{
67 cosmos::sprintf(
"/proc/%d/fd", cosmos::to_integral(pid))};
69 for (
const auto &entry: dir) {
70 if (entry.isDotEntry())
74 auto fd = std::stoi(entry.name());
75 ret.insert(cosmos::FileNum{fd});
80 }
catch (
const cosmos::ApiError &ex) {
94 else if (type ==
"socket")
96 else if (type ==
"eventfd")
97 return Type::EVENT_FD;
98 else if (type ==
"eventpoll")
100 else if (type ==
"pidfd")
102 else if (type ==
"signalfd")
103 return Type::SIGNAL_FD;
104 else if (type ==
"timerfd")
105 return Type::TIMER_FD;
106 else if (type ==
"inotify")
107 return Type::INOTIFY;
108 else if (type ==
"bpf-map")
109 return Type::BPF_MAP;
110 else if (type ==
"bpf-prog")
111 return Type::BPF_PROG;
112 else if (type ==
"perf_event")
113 return Type::PERF_EVENT;
116 LOG_WARN(
"Unknown /proc/<pid>/fd file type '" << type <<
"' encountered");
117 return Type::UNKNOWN;
125bool parse_type_info(
const std::string &type_info,
FDInfo &info) {
127 if (!type_info.empty() && type_info[0] ==
'/') {
129 info.path = type_info;
138 auto parts = cosmos::split(type_info,
":", cosmos::SplitFlags{}, 1);
139 if (parts.size() != 2) {
143 if (
auto type = parts[0];
type ==
"anon_inode") {
146 auto real_type = cosmos::stripped(parts[1],
"[]");
147 info.type = to_fd_info_type(real_type);
149 info.type = to_fd_info_type(
type);
151 const auto inode_str = cosmos::stripped(parts[1],
"[]");
154 auto inode = std::stoul(inode_str);
155 info.inode = cosmos::Inode{inode};
158 LOG_WARN(__FUNCTION__ <<
": non-numerical inode \""
159 << inode_str <<
"\"?!");
174void parse_fd_info(
const cosmos::ProcessID pid,
FDInfo &info) {
176 cosmos::sprintf(
"/proc/%d/fdinfo/%d",
177 cosmos::to_integral(pid),
178 cosmos::to_integral(info.fd)),
179 cosmos::OpenMode::READ_ONLY
182 cosmos::InputStreamAdaptor fdinfo_stream{fdinfo};
185 while (std::getline(fdinfo_stream, line).good()) {
186 auto parts = cosmos::split(line,
":",
187 cosmos::SplitFlag::STRIP_PARTS,
189 if (parts.size() != 2)
191 else if (parts[0] !=
"flags")
195 auto raw_flags = std::stoi(parts[1],
nullptr, 8);
196 const cosmos::OpenMode mode{
197 raw_flags & (O_RDONLY|O_WRONLY|O_RDWR)};
198 const cosmos::OpenFlags flags{
199 raw_flags & ~(cosmos::to_integral(mode))};
205 throw cosmos::RuntimeError{
"no flags found"};
211 std::vector<FDInfo> ret;
212 cosmos::DirStream dir;
213 const auto proc_pid_fd = cosmos::sprintf(
"/proc/%d/fd",
214 cosmos::to_integral(pid));
217 dir.open(proc_pid_fd);
218 }
catch (
const cosmos::ApiError &ex) {
223 for (
const auto &entry: dir) {
224 if (entry.isDotEntry())
230 auto fd = std::stoi(entry.name());
231 info.
fd = cosmos::FileNum{fd};
234 LOG_WARN(__FUNCTION__ <<
": " << proc_pid_fd
235 <<
" non-numerical entry "
236 << entry.name() <<
"?!");
241 auto type_info = cosmos::fs::read_symlink_at(
245 if (!parse_type_info(type_info, info)) {
246 LOG_WARN(__FUNCTION__ <<
": " << proc_pid_fd
247 <<
" failed to parse type info \""
248 << type_info <<
"\"");
251 }
catch (
const std::exception &ex) {
252 LOG_WARN(__FUNCTION__ <<
": " << proc_pid_fd
253 <<
" failed to read symlink: "
258 parse_fd_info(pid, info);
259 }
catch (
const std::exception &ex) {
260 LOG_WARN(__FUNCTION__ <<
": " << proc_pid_fd
261 <<
" failed to read fdinfo: "
272 auto it = SYSTEM_CALL_NAME_MAP.find(name);
274 if (it == SYSTEM_CALL_NAME_MAP.end())
282 case ABI::X86_64:
return cosmos::arch::X86_64;
283 case ABI::I386:
return cosmos::arch::I386;
284 case ABI::AARCH64:
return cosmos::arch::AARCH64;
285 default:
return false;
289const char* get_abi_label(
const ABI abi) {
291 case ABI::X86_64:
return "x86_64";
292 case ABI::I386:
return "i386";
294 case ABI::AARCH64:
return "aarch64";
295 default:
return "unknown";
305 return {ABI::I386, ABI::X86_64,
ABI::X32};
306#elif defined(COSMOS_I386)
308#elif defined(COSMOS_AARCH64)
316 return {ABI::AARCH64};
318 throw cosmos::RuntimeError{
"no ABIs supported on this platform?!"};
323 std::function<
bool(
const std::string&)> parser) {
324 const auto path = cosmos::proc::build_proc_path(pid, subpath);
326 std::ifstream fs{path};
329 throw cosmos::RuntimeError{
"failed to open proc file"};
334 while (std::getline(fs, line).good()) {
341 throw cosmos::RuntimeError{
"failed to read proc file"};
345void parse_proc_file(
const Tracee &tracee,
const std::string_view subpath, std::function<
bool(
const std::string&)> parser) {
Base class for traced processes.
KernelErrno
Errno values that can appear in tracing context.
const char * get_ptrace_event_str(const cosmos::ptrace::Event event)
Returns a string label for the given event.
@ X32
X86_64 with 32-bit pointers.
std::vector< FDInfo > get_fd_infos(const cosmos::ProcessID pid)
Obtain detailed information about currently open file descriptors according to /proc/<pid>/fd.
std::array< ABI, SUPPORTED_ABIS > get_supported_abis()
Returns a list of ABIs supported on the current platform.
std::optional< SystemCallNr > lookup_system_call(const std::string_view name)
Returns the SystemCallNr for the given system call name, if it exists.
const char * get_errno_label(const cosmos::Errno err)
Returns a short errno label like ENOENT for the given errno integer.
const char * get_kernel_errno_label(const KernelErrno err)
Returns a short errno label for extended KernelErrno codes.
std::set< cosmos::FileNum > get_currently_open_fds(const cosmos::ProcessID pid)
Returns the currently open file descriptors according to /proc/<pid>/fd.
void parse_proc_file(const cosmos::ProcessID pid, const std::string_view subpath, std::function< bool(const std::string &)> parser)
Parse a proc file of the given process using the given functor.
bool is_default_abi(const ABI abi)
Returns whether the given ABI is default ABI for this system.
Contextual information about a file descriptor in a Tracee.
cosmos::FileNum fd
the actual file descriptor number.
Type
Different types of file descriptors.
@ FS_PATH
a path opened on the file system (this can still be a device special file, named pipe,...