6#include <sys/resource.h>
10#include <cosmos/formatting.hxx>
11#include <cosmos/fs/filesystem.hxx>
12#include <cosmos/proc/ptrace.hxx>
13#include <cosmos/string.hxx>
14#include <cosmos/utils.hxx>
17#include <clues/format.hxx>
18#include <clues/macros.h>
19#include <clues/SystemCall.hxx>
20#include <clues/utils.hxx>
21#include <clues/private/kernel/sigaction.hxx>
23using namespace std::string_literals;
25namespace clues::format {
27std::string signal(
const cosmos::SignalNr signal,
const bool verbose) {
30 const auto SIGRTMIN_PRIV = SIGRTMIN - 2;
32 if (
const auto raw = cosmos::to_integral(signal); raw < SIGRTMIN_PRIV || raw > SIGRTMAX) {
34 CASE_ENUM_TO_STR(SIGINT);
35 CASE_ENUM_TO_STR(SIGTERM);
36 CASE_ENUM_TO_STR(SIGHUP);
37 CASE_ENUM_TO_STR(SIGQUIT);
38 CASE_ENUM_TO_STR(SIGILL);
39 CASE_ENUM_TO_STR(SIGABRT);
40 CASE_ENUM_TO_STR(SIGFPE);
41 CASE_ENUM_TO_STR(SIGKILL);
42 CASE_ENUM_TO_STR(SIGPIPE);
43 CASE_ENUM_TO_STR(SIGSEGV);
44 CASE_ENUM_TO_STR(SIGALRM);
45 CASE_ENUM_TO_STR(SIGUSR1);
46 CASE_ENUM_TO_STR(SIGUSR2);
47 CASE_ENUM_TO_STR(SIGCONT);
48 CASE_ENUM_TO_STR(SIGSTOP);
49 CASE_ENUM_TO_STR(SIGTSTP);
50 CASE_ENUM_TO_STR(SIGTTIN);
51 CASE_ENUM_TO_STR(SIGTTOU);
52 CASE_ENUM_TO_STR(SIGTRAP);
53 CASE_ENUM_TO_STR(SIGBUS);
54 CASE_ENUM_TO_STR(SIGSTKFLT);
55 CASE_ENUM_TO_STR(SIGCHLD);
56 CASE_ENUM_TO_STR(SIGIO);
57 CASE_ENUM_TO_STR(SIGPROF);
58 CASE_ENUM_TO_STR(SIGSYS);
59 CASE_ENUM_TO_STR(SIGWINCH);
60 CASE_ENUM_TO_STR(SIGPWR);
61 CASE_ENUM_TO_STR(SIGURG);
62 CASE_ENUM_TO_STR(SIGXCPU);
63 CASE_ENUM_TO_STR(SIGVTALRM);
64 CASE_ENUM_TO_STR(SIGXFSZ);
65 default: ss <<
"unknown (" << raw <<
")";
break;
67 }
else if (raw >= SIGRTMIN_PRIV && raw < SIGRTMIN) {
68 ss <<
"glibc internal signal";
70 ss <<
"SIGRT" << raw - SIGRTMIN;
74 ss <<
" (" << cosmos::Signal{signal}.name() <<
")";
80std::string signal_set(
const cosmos::SigSet &set) {
85 for (
int signum = 1; signum < SIGRTMAX; signum++) {
86 const auto sig = cosmos::SignalNr{signum};
88 if (set.isSet(cosmos::Signal{sig})) {
89 ss << format::signal(sig,
false) <<
", ";
94 if (cosmos::is_suffix(ret,
", ")) {
95 ret = ret.substr(0, ret.size() - 2);
101std::string saflags(
const int flags) {
102#define chk_sa_flag(FLAG) if (flags & FLAG) { \
103 if (!first) ss << "|";\
113 std::stringstream ss;
116 chk_sa_flag(SA_NOCLDSTOP);
117 chk_sa_flag(SA_NOCLDWAIT);
118 chk_sa_flag(SA_NODEFER);
119 chk_sa_flag(SA_ONSTACK);
120 chk_sa_flag(SA_RESETHAND);
121 chk_sa_flag(SA_RESTART);
122 chk_sa_flag(SA_SIGINFO);
123 chk_sa_flag(SA_RESTORER);
128std::string limit(
const uint64_t lim) {
129 if (lim == RLIM_INFINITY)
130 return "RLIM_INFINITY";
134#if RLIM_INFINITY != RLIM64_INFINITY
135 else if (lim == RLIM64_INFINITY)
136 return "RLIM64_INFINITY";
138 else if ((lim % 1024) == 0)
139 return std::to_string(lim / 1024) +
" * " +
"1024";
141 return std::to_string(lim);
144std::string si_code(
const cosmos::SigInfo::Source src) {
145 const auto raw = cosmos::to_integral(src);
148 CASE_ENUM_TO_STR(SI_USER);
149 CASE_ENUM_TO_STR(SI_KERNEL);
150 CASE_ENUM_TO_STR(SI_QUEUE);
151 CASE_ENUM_TO_STR(SI_TIMER);
152 CASE_ENUM_TO_STR(SI_MESGQ);
153 CASE_ENUM_TO_STR(SI_ASYNCIO);
154 CASE_ENUM_TO_STR(SI_SIGIO);
155 CASE_ENUM_TO_STR(SI_TKILL);
156 default:
return std::to_string(raw);
160std::string si_reason(
const cosmos::SigInfo::SysData::Reason reason) {
161 const auto raw = cosmos::to_integral(reason);
164 CASE_ENUM_TO_STR(SYS_SECCOMP);
165 CASE_ENUM_TO_STR(SYS_USER_DISPATCH);
166 default:
return std::to_string(raw);
170std::string si_reason(
const cosmos::SigInfo::SegfaultData::Reason reason) {
171 const auto raw = cosmos::to_integral(reason);
174 CASE_ENUM_TO_STR(SEGV_MAPERR);
175 CASE_ENUM_TO_STR(SEGV_ACCERR);
176 CASE_ENUM_TO_STR(SEGV_BNDERR);
177 CASE_ENUM_TO_STR(SEGV_PKUERR);
178 CASE_ENUM_TO_STR(SEGV_ACCADI);
179 CASE_ENUM_TO_STR(SEGV_ADIDERR);
180 CASE_ENUM_TO_STR(SEGV_ADIPERR);
181 CASE_ENUM_TO_STR(SEGV_MTEAERR);
182 CASE_ENUM_TO_STR(SEGV_MTESERR);
184 CASE_ENUM_TO_STR(SEGV_CPERR);
186 default:
return std::to_string(raw);
190std::string si_reason(
const cosmos::SigInfo::BusData::Reason reason) {
191 const auto raw = cosmos::to_integral(reason);
194 CASE_ENUM_TO_STR(BUS_ADRALN);
195 CASE_ENUM_TO_STR(BUS_ADRERR);
196 CASE_ENUM_TO_STR(BUS_OBJERR);
197 CASE_ENUM_TO_STR(BUS_MCEERR_AR);
198 CASE_ENUM_TO_STR(BUS_MCEERR_AO);
199 default:
return std::to_string(raw);
203std::string ptrace_arch(
const cosmos::ptrace::Arch arch) {
204 const auto raw = cosmos::to_integral(arch);
207 CASE_ENUM_TO_STR(AUDIT_ARCH_X86_64);
208 CASE_ENUM_TO_STR(AUDIT_ARCH_I386);
209 default:
return std::to_string(raw);
213std::string child_event(
const cosmos::SigInfo::ChildData::Event event) {
214 const auto raw = cosmos::to_integral(event);
217 CASE_ENUM_TO_STR(CLD_EXITED);
218 CASE_ENUM_TO_STR(CLD_KILLED);
219 CASE_ENUM_TO_STR(CLD_DUMPED);
220 CASE_ENUM_TO_STR(CLD_TRAPPED);
221 CASE_ENUM_TO_STR(CLD_STOPPED);
222 CASE_ENUM_TO_STR(CLD_CONTINUED);
223 default:
return std::to_string(raw);
227std::string si_reason(
const cosmos::SigInfo::PollData::Reason reason) {
228 const auto raw = cosmos::to_integral(reason);
231 CASE_ENUM_TO_STR(POLL_IN);
232 CASE_ENUM_TO_STR(POLL_OUT);
233 CASE_ENUM_TO_STR(POLL_MSG);
234 CASE_ENUM_TO_STR(POLL_ERR);
235 CASE_ENUM_TO_STR(POLL_PRI);
236 CASE_ENUM_TO_STR(POLL_HUP);
237 default:
return std::to_string(raw);
241std::string si_reason(
const cosmos::SigInfo::IllData::Reason reason) {
242 const auto raw = cosmos::to_integral(reason);
245 CASE_ENUM_TO_STR(ILL_ILLOPC);
246 CASE_ENUM_TO_STR(ILL_ILLOPN);
247 CASE_ENUM_TO_STR(ILL_ILLADR);
248 CASE_ENUM_TO_STR(ILL_ILLTRP);
249 CASE_ENUM_TO_STR(ILL_PRVOPC);
250 CASE_ENUM_TO_STR(ILL_PRVREG);
251 CASE_ENUM_TO_STR(ILL_COPROC);
252 CASE_ENUM_TO_STR(ILL_BADSTK);
253 CASE_ENUM_TO_STR(ILL_BADIADDR);
254 default:
return std::to_string(raw);
258std::string si_reason(
const cosmos::SigInfo::FPEData::Reason reason) {
259 const auto raw = cosmos::to_integral(reason);
262 CASE_ENUM_TO_STR(FPE_INTDIV);
263 CASE_ENUM_TO_STR(FPE_INTOVF);
264 CASE_ENUM_TO_STR(FPE_FLTDIV);
265 CASE_ENUM_TO_STR(FPE_FLTOVF);
266 CASE_ENUM_TO_STR(FPE_FLTUND);
267 CASE_ENUM_TO_STR(FPE_FLTRES);
268 CASE_ENUM_TO_STR(FPE_FLTINV);
269 CASE_ENUM_TO_STR(FPE_FLTSUB);
270 CASE_ENUM_TO_STR(FPE_FLTUNK);
271 CASE_ENUM_TO_STR(FPE_CONDTRAP);
272 default:
return std::to_string(raw);
276std::string poll_event(
const cosmos::PollEvent event) {
277 const auto raw = cosmos::to_integral(event);
280 CASE_ENUM_TO_STR(POLLIN);
281 CASE_ENUM_TO_STR(POLLPRI);
282 CASE_ENUM_TO_STR(POLLOUT);
283 CASE_ENUM_TO_STR(POLLRDHUP);
284 CASE_ENUM_TO_STR(POLLERR);
285 CASE_ENUM_TO_STR(POLLHUP);
286 CASE_ENUM_TO_STR(POLLNVAL);
287 CASE_ENUM_TO_STR(POLLWRBAND);
288 default:
return std::to_string(raw);
292std::string poll_events(
const cosmos::PollEvents events) {
293 constexpr auto HIGHEST = 1 << (
sizeof(cosmos::PollEvent) * 8 - 1);
298 const auto flag = cosmos::PollEvent{
static_cast<cosmos::PollEvents::EnumBaseType
>(bit)};
304 ret += poll_event(flag);
308 }
while (bit != HIGHEST);
313std::string sig_info(
const cosmos::SigInfo &info) {
314 using SigInfo = cosmos::SigInfo;
315 std::stringstream ss;
317 auto add_process_ctx = [&ss](
const cosmos::ProcessCtx ctx) {
318 ss <<
", si_pid=" << cosmos::to_integral(ctx.pid);
319 ss <<
", si_uid=" << cosmos::to_integral(ctx.uid);
322 auto add_custom_data = [&ss](
const SigInfo::CustomData data) {
323 ss <<
", si_int=" << data.asInt();
324 ss <<
", si_ptr=" << data.asPtr();
327 auto add_fault_data = [&ss](
auto data) {
329 ss <<
" (" << format::si_reason(data.reason) <<
")";
330 ss <<
", si_addr=" << data.addr;
333 ss << info.sigNr() <<
" {";
334 if (info.source() != SigInfo::Source::KERNEL ||
335 info.raw()->si_code == SI_KERNEL) {
336 ss <<
"si_code=" << format::si_code(info.source());
339 ss <<
"si_code=" << info.raw()->si_code;
342 if (
auto user_data = info.userSigData(); user_data) {
343 add_process_ctx(user_data->sender);
344 }
else if (
auto queue_data = info.queueSigData(); queue_data) {
345 add_process_ctx(queue_data->sender);
346 add_custom_data(queue_data->data);
347 }
else if (
auto msg_queue_data = info.msgQueueData(); msg_queue_data) {
348 add_process_ctx(msg_queue_data->msg_sender);
349 add_custom_data(msg_queue_data->data);
350 }
else if (
auto timer_data = info.timerData(); timer_data) {
351 ss <<
", si_timerid=" << cosmos::to_integral(timer_data->id);
352 ss <<
", si_overrun=" << timer_data->overrun;
353 }
else if (
auto sys_data = info.sysData(); sys_data) {
354 ss <<
", reason=" << format::si_reason(sys_data->reason);
355 ss <<
", si_addr=" << sys_data->call_addr;
356 ss <<
", si_syscall=" << sys_data->call_nr
359 ss <<
", si_arch=" << format::ptrace_arch(sys_data->arch);
360 ss <<
", si_errno=" << sys_data->error;
361 }
else if (
auto child_data = info.childData(); child_data) {
363 ss <<
" (" << format::child_event(child_data->event) <<
")";
364 add_process_ctx(child_data->child);
365 ss <<
", si_status=" << info.raw()->si_status;
366 if (child_data->signal) {
367 ss <<
" (" << *child_data->signal <<
")";
369 ss <<
" (exit code)";
371 if (child_data->user_time) {
372 ss <<
", si_utime=" << cosmos::to_integral(*child_data->user_time);
374 if (child_data->system_time) {
375 ss <<
", si_stime=" << cosmos::to_integral(*child_data->system_time);
377 }
else if (
auto poll_data = info.pollData(); poll_data) {
379 ss <<
" (" << format::si_reason(poll_data->reason) <<
")";
380 ss <<
", si_fd=" << cosmos::to_integral(poll_data->fd);
381 ss <<
", si_band=" << format::poll_events(poll_data->events);
382 }
else if (
auto ill_data = info.illData(); ill_data) {
383 add_fault_data(*ill_data);
384 }
else if (
auto fpe_data = info.fpeData(); fpe_data) {
385 add_fault_data(*fpe_data);
386 }
else if (
auto segv_data = info.segfaultData(); segv_data) {
387 add_fault_data(*segv_data);
388 if (
auto bound = segv_data->bound; bound) {
389 ss <<
", si_lower=" << bound->lower;
390 ss <<
", si_upper=" << bound->upper;
392 if (
auto key = segv_data->key; key) {
393 ss <<
", si_pkey=" << cosmos::to_integral(*key);
395 }
else if (
auto bus_data = info.busData(); bus_data) {
396 add_fault_data(*bus_data);
397 if (
auto lsb = bus_data->addr_lsb; lsb) {
398 ss <<
", si_addr_lsb=" << *lsb;
407std::string event(
const cosmos::ChildState &state) {
408 std::stringstream ss;
410 ss <<
"PID " << cosmos::to_integral(state.child.pid) <<
" ";
412 if (state.exited()) {
413 ss <<
"EXITED with " << cosmos::to_integral(*state.status);
414 }
else if (state.trapped()) {
416 if (state.signal->isPtraceEventStop()) {
417 const auto [_, event] = cosmos::ptrace::decode_event(*state.signal);
423 else if (state.dumped())
425 else if (state.continued())
427 else if (state.stopped())
429 ss <<
"(" << state.signal->name() <<
")";
435std::string_view file_type(
const cosmos::FileType type) {
436 switch (cosmos::to_integral(type.raw())) {
437 CASE_ENUM_TO_STR(S_IFSOCK);
438 CASE_ENUM_TO_STR(S_IFLNK);
439 CASE_ENUM_TO_STR(S_IFREG);
440 CASE_ENUM_TO_STR(S_IFBLK);
441 CASE_ENUM_TO_STR(S_IFDIR);
442 CASE_ENUM_TO_STR(S_IFCHR);
443 CASE_ENUM_TO_STR(S_IFIFO);
444 default:
return "???";
448std::string file_mode_numeric(
const cosmos::FileModeBits mode) {
453 return static_cast<std::string
>(cosmos::OctNum{mode.raw(), 3});
456std::string device_id(
const cosmos::DeviceID
id) {
457 const auto [major, minor] = cosmos::fs::split_device_id(
id);
458 return cosmos::sprintf(
"%s:%s",
459 static_cast<std::string
>(cosmos::HexNum{cosmos::to_integral(major), 2}).c_str(),
460 static_cast<std::string
>(cosmos::HexNum{cosmos::to_integral(minor), 2}).c_str());
464std::string timespec(
const struct timespec &ts,
const bool only_secs) {
465 std::stringstream ss;
467 ss << ts.tv_sec <<
"s";
469 ss <<
"{" << ts.tv_sec <<
"s, " << ts.tv_nsec <<
"ns}";
474std::string timeval(
const struct timeval &tv,
const bool only_secs) {
475 std::stringstream ss;
477 ss << tv.tv_sec <<
"s";
479 ss <<
"{" << tv.tv_sec <<
"s, " << tv.tv_usec <<
"us}";
485 public cosmos::FormattedNumber<unsigned char> {
486 HexChar(
const unsigned char ch) :
487 cosmos::FormattedNumber<unsigned char>{ch, 2, [](std::ostream &o){ o << std::hex; },
"\\x"}
491std::string control_char(
const char ch) {
493 case '\n':
return "\\n";
494 case '\r':
return "\\r";
495 case '\v':
return "\\v";
496 case '\t':
return "\\t";
497 case '\f':
return "\\f";
498 case '\b':
return "\\b";
499 default:
return "\\?";
503std::string buffer(
const uint8_t *buffer,
const size_t len) {
504 std::stringstream ss;
519 for (
size_t idx = 0; idx < len; idx++) {
520 const auto ch =
static_cast<unsigned char>(buffer[idx]);
522 if (std::isprint(ch)) {
524 }
else if (std::isspace(ch)) {
525 ss << control_char(ch);
537 if (ptr == ForeignPtr::NO_POINTER)
540 std::stringstream ss;
541 ss << reinterpret_cast<void*>(cosmos::to_integral(ptr));
546std::string pointer(
const ForeignPtr ptr,
const std::string_view data) {
547 if (ptr == ForeignPtr::NO_POINTER)
550 std::stringstream ss;
552 ss << reinterpret_cast<void*>(cosmos::to_integral(ptr)) <<
" → " <<
"[" << data <<
"]";
557std::string_view fd_type(
const FDInfo &info) {
562 CASE_ENUM_TO_STR(INVALID);
563 CASE_ENUM_TO_STR(FS_PATH);
564 CASE_ENUM_TO_STR(EVENT_FD);
565 CASE_ENUM_TO_STR(TIMER_FD);
566 CASE_ENUM_TO_STR(SIGNAL_FD);
567 CASE_ENUM_TO_STR(SOCKET);
568 CASE_ENUM_TO_STR(EPOLL);
569 CASE_ENUM_TO_STR(PIPE);
570 CASE_ENUM_TO_STR(INOTIFY);
571 CASE_ENUM_TO_STR(PID_FD);
572 CASE_ENUM_TO_STR(BPF_MAP);
573 CASE_ENUM_TO_STR(BPF_PROG);
574 CASE_ENUM_TO_STR(PERF_EVENT);
575 CASE_ENUM_TO_STR(UNKNOWN);
579std::string fd_info(
const FDInfo &info) {
582 std::string extra_info;
585 case FS_PATH:
return cosmos::sprintf(
"<%s>", info.path.c_str());
587 const bool read_end = info.mode == cosmos::OpenMode::READ_ONLY;
588 extra_info =
","s + (read_end ?
"ro"s :
"wronly"s);
591 default:
return cosmos::sprintf(
"<%s%s>", &fd_type(info)[0], extra_info.c_str());
std::string_view name() const
Returns the system call's human readable name.
const char * get_ptrace_event_str(const cosmos::ptrace::Event event)
Returns a string label for the given event.
SystemCallNr
Abstract system call number usable across architectures and ABIs.
ForeignPtr
Strongly typed opaque pointer to tracee memory.
Type
Different types of file descriptors.