libclues
Linux C++ Tracing Library
Loading...
Searching...
No Matches
clues::EventConsumer Class Reference

Callback interface for consumers of tracing events. More...

#include <EventConsumer.hxx>

+ Inheritance diagram for clues::EventConsumer:

Public Types

enum class  StatusFlag {
  INTERRUPTED = 1 << 0 , RESUMED = 1 << 1 , LOST_TO_MT_EXIT = 1 << 2 , ABI_CHANGED = 1 << 3 ,
  CLONED_THREAD = 1 << 4
}
 Different status flags that can appear in callbacks. More...
 
using StatusFlags = cosmos::BitMask<StatusFlag>
 

Protected Member Functions

virtual void syscallEntry (Tracee &tracee, const SystemCall &sc, const StatusFlags flags)
 A system call is about to be executed in the Tracee.
 
virtual void syscallExit (Tracee &tracee, const SystemCall &sc, const StatusFlags flags)
 A system call has been finished.
 
virtual void attached (Tracee &tracee)
 The tracee is now properly attached to.
 
virtual void signaled (Tracee &tracee, const cosmos::SigInfo &info)
 The tracee has received a signal.
 
virtual void stopped (Tracee &tracee)
 The tracee entered group-stop due to a stopping signal.
 
virtual void resumed (Tracee &tracee)
 The tracee resumed due to SIGCONT.
 
virtual void exited (Tracee &tracee, const cosmos::WaitStatus status, const StatusFlags flags)
 The tracee is about to end execution.
 
virtual void disappeared (Tracee &tracee, const cosmos::ChildState &data)
 The tracee disappeared for unclear reasons.
 
virtual void newExecutionContext (Tracee &tracee, const std::string &old_executable, const cosmos::StringVector &old_cmdline, const std::optional< cosmos::ProcessID > old_pid)
 A new program is executed in the tracee.
 
virtual void newChildProcess (Tracee &parent, Tracee &child, const cosmos::ptrace::Event event, const StatusFlags flags)
 A new child process has been created.
 
virtual void vforkComplete (Tracee &parent, TraceePtr child)
 A vfork() in parent for child completed.
 

Friends

class Tracee
 
class Engine
 

Detailed Description

Callback interface for consumers of tracing events.

This is the main point of interaction between the Engine class and its users. Tracing events for all active tracees will be delivered via this interface.

libclues currently operates in a single-threaded mode only. This means there will only one callback ever be active at any given time. Blocking should be avoided in the context of callbacks to prevent tracing to get stuck.

Clients only need to override those methods that they are interested in. If FollowChildren is active, then the attached() callback offers the possibility to detach from automatically attached child processes. Otherwise they will be fully traced as well.

Definition at line 32 of file EventConsumer.hxx.

Member Typedef Documentation

◆ StatusFlags

using clues::EventConsumer::StatusFlags = cosmos::BitMask<StatusFlag>

Definition at line 51 of file EventConsumer.hxx.

Member Enumeration Documentation

◆ StatusFlag

Different status flags that can appear in callbacks.

Enumerator
INTERRUPTED 

A system call was interrupted (only appears during syscallExit()).

RESUMED 

A previously interrupted system call is resumed (only appears during syscallEntry()).

LOST_TO_MT_EXIT 

An exit occurs because another thread called execve() or exit() (only appears in exited()).

ABI_CHANGED 

The system call ABI changed since the last observed system call.

CLONED_THREAD 

used in newChildProcess() to indicate that a new thread has been created.

Definition at line 38 of file EventConsumer.hxx.

38 {
40 INTERRUPTED = 1 << 0,
42 RESUMED = 1 << 1,
44 LOST_TO_MT_EXIT = 1 << 2,
46 ABI_CHANGED = 1 << 3,
48 CLONED_THREAD = 1 << 4,
49 };

Member Function Documentation

◆ attached()

virtual void clues::EventConsumer::attached ( Tracee & tracee)
inlineprotectedvirtual

The tracee is now properly attached to.

This should be the first call that that is visible for a tracee. It occurs when the ptrace() relationship is established and a defined tracing state has been reached. The Tracee will be in PTRACE_EVENT_STOP.

The following situations can cause an attached() callback:

  • tracee was actively registered via Engine::addTracee().
  • an already present tracee created a new thread or child process. This is preceded by newChildProcess().
  • an existing process has been attached to via Engine::addTracee(const cosmos::ProcessID, ..., AttachThreads{true}). Any additional threads that exist in the process will then automatically be attached to. tracee.isInitiallyAttachedThread() will return true in this case.

Reimplemented in clues::TermTracer.

Definition at line 135 of file EventConsumer.hxx.

135 {
136 (void)tracee;
137 }

◆ disappeared()

virtual void clues::EventConsumer::disappeared ( Tracee & tracee,
const cosmos::ChildState & data )
inlineprotectedvirtual

The tracee disappeared for unclear reasons.

This callback can occur in a number of special situations like:

  • another thread of the same process called exit(). This is not always caught as an exit event, which would lead to a call to exited(). This is especially the case when the other thread which calls exit() is not also traced.
  • generally the ptrace() documentation says that a tracee can disappear at any time without warning, which is unlucky. libclues attempts to provide as much contextual information as possible. In the case of disappeared(), the cause remains uncertain, however.

When this call occurs then the tracee can no longer be accessed via the tracing API. data still tells whether the tracee exited regularly or due to a signal.

Reimplemented in clues::TermTracer.

Definition at line 196 of file EventConsumer.hxx.

196 {
197 (void)tracee;
198 (void)data;
199 }

◆ exited()

virtual void clues::EventConsumer::exited ( Tracee & tracee,
const cosmos::WaitStatus status,
const StatusFlags flags )
inlineprotectedvirtual

The tracee is about to end execution.

The tracee is about to either exit regularly, to be killed by a signal or to disappear due to an execve() in a multi-threaded process.

When this callback occurs the tracee can still be inspected using ptrace(). Once execution is continued the tracer <-> tracee relationship is lost.

If the exit happens due to an execve in a multi-threaded process then Status::LOST_TO_MT_EXIT is set in flags.

Reimplemented in clues::TermTracer.

Definition at line 172 of file EventConsumer.hxx.

172 {
173 (void)tracee;
174 (void)status;
175 (void)flags;
176 }

◆ newChildProcess()

virtual void clues::EventConsumer::newChildProcess ( Tracee & parent,
Tracee & child,
const cosmos::ptrace::Event event,
const StatusFlags flags )
inlineprotectedvirtual

A new child process has been created.

The existing tracee parent has created a new child process, which has automatically been attached to and is now represented in child.

Different ways to create a child process exist, these are differentiated via event. Note that some forms of clone() calls will appear as cosmos::ptrace::Event::FORK or cosmos::ptrace::Event::VFORK instead of cosmos::ptrace::Event::CLONE (when the clone() exit signal is set to SIGCHILD).

cosmos::ptrace::Event::VFORK_DONE occurs when the child process exited or exec()'d and can be ignored if there is no need for it.

StatusFlag::CLONED_THREAD will be set in flags in case the new child process is a thread of parent.

Reimplemented in clues::TermTracer.

Definition at line 260 of file EventConsumer.hxx.

264 {
265 (void)parent;
266 (void)child;
267 (void)event;
268 (void)flags;
269 }

◆ newExecutionContext()

virtual void clues::EventConsumer::newExecutionContext ( Tracee & tracee,
const std::string & old_executable,
const cosmos::StringVector & old_cmdline,
const std::optional< cosmos::ProcessID > old_pid )
inlineprotectedvirtual

A new program is executed in the tracee.

This call occurs after a successful execve() by the tracee.

The new executable path and command line can be retrieved via Tracee::executable() and Tracee::cmdLine(). The previous values are provided as input parameters.

The callee can decide to stop tracing (by detaching) at this point to prevent following the new tracing context.

If the tracee's process was multi-threaded then there is more complexity involved:

  • all but one thread will have exited at this point. Only the main process ID (main thread PID) will remain.
  • The thread that caused the execve() can be a different thread. In this case the different thread will receive a new PID personality (it will receive the main thread PID).
  • In case of a personality change, former_pid contains the former PID that the exec'ing thread had, which is now continuing as the main thread of the new execution context.
  • the current implementation of libclues will attempt to reuse the main thread's Tracee object even if a personality change happened. If the main thread was not traced at all then the exec()'ing thread's Tracee object will be reused. Due to this it is best to rely on the PIDs only (not Tracee pointers) to identify the new/old context.

Reimplemented in clues::TermTracer.

Definition at line 230 of file EventConsumer.hxx.

234 {
235 (void)tracee;
236 (void)old_cmdline;
237 (void)old_executable;
238 (void)old_pid;
239 }

◆ resumed()

virtual void clues::EventConsumer::resumed ( Tracee & tracee)
inlineprotectedvirtual

The tracee resumed due to SIGCONT.

Definition at line 155 of file EventConsumer.hxx.

155 {
156 (void)tracee;
157 }

◆ signaled()

virtual void clues::EventConsumer::signaled ( Tracee & tracee,
const cosmos::SigInfo & info )
inlineprotectedvirtual

The tracee has received a signal.

This callback notifies about signals being delivered to the tracee.

Reimplemented in clues::TermTracer.

Definition at line 144 of file EventConsumer.hxx.

144 {
145 (void)tracee;
146 (void)info;
147 };

◆ stopped()

virtual void clues::EventConsumer::stopped ( Tracee & tracee)
inlineprotectedvirtual

The tracee entered group-stop due to a stopping signal.

Reimplemented in clues::TermTracer.

Definition at line 150 of file EventConsumer.hxx.

150 {
151 (void)tracee;
152 }

◆ syscallEntry()

virtual void clues::EventConsumer::syscallEntry ( Tracee & tracee,
const SystemCall & sc,
const StatusFlags flags )
inlineprotectedvirtual

A system call is about to be executed in the Tracee.

At this stage only the type of system call as well system call parameters of ItemType::PARAM_IN or ItemType::PARAM_IN_OUT have useful values. Any out parameters and the return value should not be inspected.

Reimplemented in clues::TermTracer.

Definition at line 62 of file EventConsumer.hxx.

62 {
63 (void)tracee;
64 (void)sc;
65 (void)flags;
66 }

◆ syscallExit()

virtual void clues::EventConsumer::syscallExit ( Tracee & tracee,
const SystemCall & sc,
const StatusFlags flags )
inlineprotectedvirtual

A system call has been finished.

If the system call failed then sc.hasErrorCode() returns true and the ErrnoResult can be inspected from sc.error().

If the system call succeeded sc.hasResultValue() returns true and any system call parameters of ItemType::PARAM_OUT or ItemType::PARAM_IN_OUT should have been updated by the kernel and can be updated and processed by the implementation.

If flags[StatusFlag::INTERRUPTED] is set, then the system call was interrupted by a signal and aborted by the kernel. Whether this happens depends on various factors, e.g. if the SA_RESTART flag is set in the Tracee for the signal which was received and also on the type of system call which is executed. If automatic system call restarting is not active then a regular EINTR error return will be observed and the Tracee has to actively deal with the situation.

libclues tries to keep track of when an automatically restarted system call will be resumed and will set flags[StatusFlag::RESUMED] during syscallEntry() accordingly. There are two different scenarios to take into account here:

  • restart_syscall() is injected by the kernel. This is the case when the signal was SIGSTOP and the system call was time-related, like clock_nanosleep(), to give userspace (libc) the chance to adjust times before resuming the system call.

    libclues looks up the original system call and will not report SystemCallNr::RESTART_SYSCALL, but the resumed system call and will set StatusFlag::RESUMED accordingly.

  • the system call is transparently restarted by the kernel. In this case the system call entry is not easily distinguishable from a completely new system call. The Tracee might have executed additional system calls in-between when an asynchronous signal handler was executed. libclues is looking for the rt_sigreturn() system call to appear to make out the end of the interruption and then looks for the next system call of the same type as the interrupted system call. When this situation is detected then StatusFlag::RESUMED is set as well.

Reimplemented in clues::TermTracer.

Definition at line 110 of file EventConsumer.hxx.

110 {
111 (void)tracee;
112 (void)sc;
113 (void)flags;
114 }

◆ vforkComplete()

virtual void clues::EventConsumer::vforkComplete ( Tracee & parent,
TraceePtr child )
inlineprotectedvirtual

A vfork() in parent for child completed.

This is a special case of newChildProcess() event for vfork(). This is reported after the vfork() is complete i.e. the child either exited or performed an execve().

If child no longer exists then it is nullptr.

Definition at line 279 of file EventConsumer.hxx.

279 {
280 (void)parent;
281 (void)child;
282 }

Friends And Related Symbol Documentation

◆ Engine

friend class Engine
friend

Definition at line 34 of file EventConsumer.hxx.

◆ Tracee

friend class Tracee
friend

Definition at line 33 of file EventConsumer.hxx.


The documentation for this class was generated from the following file: