From 0286160b62dd4871ddddd89276398739d7d737b0 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Tue, 10 Aug 2021 21:02:59 +0200 Subject: Kernel: Add syscall performance event type This allows tracing the syscalls made by a thread through the kernel's performance event framework, which is similar in principle to strace. Currently, this merely logs a stack backtrace to the current thread's performance event buffer whenever a syscall is made, if profiling is enabled. Future improvements could include tracing the arguments and the return value, for example. --- Kernel/PerformanceEventBuffer.cpp | 5 +++++ Kernel/PerformanceManager.h | 11 +++++++++++ Kernel/Syscall.cpp | 3 +++ Kernel/UnixTypes.h | 1 + Userland/Libraries/LibC/serenity.h | 1 + Userland/Utilities/profile.cpp | 4 +++- 6 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Kernel/PerformanceEventBuffer.cpp b/Kernel/PerformanceEventBuffer.cpp index 0e5e3cb3a4..f461ad8db9 100644 --- a/Kernel/PerformanceEventBuffer.cpp +++ b/Kernel/PerformanceEventBuffer.cpp @@ -135,6 +135,8 @@ KResult PerformanceEventBuffer::append_with_ip_and_bp(ProcessID pid, ThreadID ti break; case PERF_EVENT_PAGE_FAULT: break; + case PERF_EVENT_SYSCALL: + break; default: return EINVAL; } @@ -226,6 +228,9 @@ bool PerformanceEventBuffer::to_json_impl(Serializer& object) const case PERF_EVENT_PAGE_FAULT: event_object.add("type", "page_fault"); break; + case PERF_EVENT_SYSCALL: + event_object.add("type", "syscall"); + break; } event_object.add("pid", event.pid); event_object.add("tid", event.tid); diff --git a/Kernel/PerformanceManager.h b/Kernel/PerformanceManager.h index 7157d0e655..c05ad84d29 100644 --- a/Kernel/PerformanceManager.h +++ b/Kernel/PerformanceManager.h @@ -119,6 +119,17 @@ public: } } + inline static void add_syscall_event(Thread& thread, const RegisterState& regs) + { + if (thread.is_profiling_suppressed()) + return; + if (auto* event_buffer = thread.process().current_perf_events_buffer()) { + [[maybe_unused]] auto rc = event_buffer->append_with_ip_and_bp( + thread.pid(), thread.tid(), + regs.ip(), regs.bp(), PERF_EVENT_SYSCALL, 0, 0, 0, nullptr); + } + } + inline static void timer_tick(RegisterState const& regs) { static Time last_wakeup; diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp index 58f6e80f1a..6c71c0b94e 100644 --- a/Kernel/Syscall.cpp +++ b/Kernel/Syscall.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,8 @@ KResultOr handle(RegisterState& regs, FlatPtr function, FlatPtr arg1, F auto& process = current_thread->process(); current_thread->did_syscall(); + PerformanceManager::add_syscall_event(*current_thread, regs); + if (function >= Function::__Count) { dbgln("Unknown syscall {} requested ({:p}, {:p}, {:p}, {:p})", function, arg1, arg2, arg3, arg4); return ENOSYS; diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index 44a3351a8a..9ebc56bca8 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -62,6 +62,7 @@ enum { PERF_EVENT_KMALLOC = 2048, PERF_EVENT_KFREE = 4096, PERF_EVENT_PAGE_FAULT = 8192, + PERF_EVENT_SYSCALL = 16384, }; #define WNOHANG 1 diff --git a/Userland/Libraries/LibC/serenity.h b/Userland/Libraries/LibC/serenity.h index 649c0914eb..a2533479d6 100644 --- a/Userland/Libraries/LibC/serenity.h +++ b/Userland/Libraries/LibC/serenity.h @@ -112,6 +112,7 @@ enum { PERF_EVENT_KMALLOC = 2048, PERF_EVENT_KFREE = 4096, PERF_EVENT_PAGE_FAULT = 8192, + PERF_EVENT_SYSCALL = 16384, }; #define PERF_EVENT_MASK_ALL (~0ull) diff --git a/Userland/Utilities/profile.cpp b/Userland/Utilities/profile.cpp index d1362ef8da..e11eac5d15 100644 --- a/Userland/Utilities/profile.cpp +++ b/Userland/Utilities/profile.cpp @@ -45,6 +45,8 @@ int main(int argc, char** argv) event_mask |= PERF_EVENT_KFREE; else if (event_type == "page_fault") event_mask |= PERF_EVENT_PAGE_FAULT; + else if (event_type == "syscall") + event_mask |= PERF_EVENT_SYSCALL; else { warnln("Unknown event type '{}' specified.", event_type); exit(1); @@ -54,7 +56,7 @@ int main(int argc, char** argv) auto print_types = [] { outln(); - outln("Event type can be one of: sample, context_switch, page_fault, kmalloc and kfree."); + outln("Event type can be one of: sample, context_switch, page_fault, syscall, kmalloc and kfree."); }; if (!args_parser.parse(argc, argv, Core::ArgsParser::FailureBehavior::PrintUsage)) { -- cgit v1.2.3