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

Specialization of Tracee that creates a new child process for tracing. More...

#include <ChildTracee.hxx>

+ Inheritance diagram for clues::ChildTracee:

Public Member Functions

 ChildTracee (Engine &engine, EventConsumer &consumer)
 Create a traced process by creating a new process from prog_args
 
void create (const cosmos::StringVector &args)
 Create the child process with the given parameters.
 
- Public Member Functions inherited from clues::Tracee
const std::string & executable () const
 
const cosmos::StringVector & cmdLine () const
 
const FDInfoMapfdInfoMap () const
 Provides access to the current knowledge about file descriptors in the tracee.
 
cosmos::ProcessID pid () const
 
bool alive () const
 
size_t maxBufferPrefetch () const
 
void setMaxBufferPrefetch (const size_t bytes)
 Sets an upper limit for the retrieval of variable-length buffer parameters in system calls.
 
size_t syscallCtr () const
 Returns the number of system calls observed so far.
 
std::optional< cosmos::Signal > stopSignal () const
 For state() == State::GROUP_STOP this returns the stopping signal that caused it.
 
State state () const
 
State prevState () const
 
bool isEnterStop () const
 
bool isExitStop () const
 
Flags flags () const
 
std::optional< cosmos::ChildState > exitData () const
 Returns possible tracee exit data.
 
virtual void attach (const FollowChildren follow_children, const AttachThreads attach_threads=AttachThreads{false})
 Logic to handle attaching to the tracee.
 
bool detach ()
 Attempt to detach the Tracee.
 
long getData (const ForeignPtr addr) const
 Reads a word of data from the tracee's memory.
 
void readString (const ForeignPtr addr, std::string &out) const
 Reads a zero-terminated C-string from the tracee.
 
void readBlob (const ForeignPtr addr, char *buffer, const size_t bytes) const
 Reads an arbitrary binary blob of fixed length from the tracee.
 
template<typename T, bool CHECK_TRIVIAL = true>
bool readStruct (const ForeignPtr addr, T &out) const
 Reads a system call struct from the tracee's address space into out.
 
template<typename VECTOR>
void readVector (const ForeignPtr pointer, VECTOR &out) const
 Reads in a zero terminated array of data items into the STL-vector like parameter out.
 
bool isThreadGroupLeader () const
 Checks in the proc file system whether the Tracee is a thread group leader.
 
bool isInitiallyAttachedThread () const
 Indicates whether this Tracee is an automatically attached thread.
 
std::optional< SystemCallNrcurrentSystemCallNr () const
 Returns the number of the currently running system call, if any.
 
const std::optional< SystemCallInfo > & currentSystemCallInfo () const
 
const Engineengine () const
 

Protected Member Functions

bool isChildProcess () const override
 Returns whether the tracee is a child process created by us.
 
void cleanupChild () override
 
- Protected Member Functions inherited from clues::Tracee
 Tracee (Engine &engine, EventConsumer &consumer, TraceePtr sibling=nullptr)
 
void processEvent (const cosmos::ChildState &data)
 Process the given ptrace event.
 
void updateExecutable ()
 
void updateCmdLine ()
 
void updateExecInfo ()
 
void syncFDsAfterExec ()
 
void changeState (const State new_state)
 
void interrupt ()
 Forces the traced process to stop.
 
void restart (const cosmos::Tracee::RestartMode mode=cosmos::Tracee::RestartMode::CONT, const std::optional< cosmos::Signal > signal={})
 Restarts the traced process, optionally delivering signal.
 
void setOptions (const cosmos::ptrace::Opts opts)
 Applies the given trace flags.
 
void seize (const cosmos::ptrace::Opts opts)
 Makes the tracee a tracee.
 
void setPID (const cosmos::ProcessID tracee)
 Sets the tracee PID.
 
template<ABI abi>
void getRegisters (RegisterSet< abi > &rs)
 Reads the current register set from the process.
 
void handleSystemCall ()
 
void handleSystemCallEntry ()
 
void handleSystemCallExit ()
 
void handleStateMismatch ()
 
void handleSignal (const cosmos::SigInfo &info)
 
void handleEvent (const cosmos::ChildState &data, const cosmos::ptrace::Event event, const cosmos::Signal signal)
 
void handleStopEvent (const cosmos::Signal signal)
 
void handleExitEvent ()
 
void handleExecEvent (const cosmos::ProcessID main_pid)
 
void handleNewChildEvent (const cosmos::ptrace::Event event)
 
void handleAttached ()
 
void syncState (Tracee &other)
 
void attachThreads ()
 
template<typename FILLER>
void fillData (ForeignPtr addr, FILLER &filler) const
 Reads data from the Tracee starting at addr and feeds it to filler until it's saturated.
 
void verifyArch ()
 Verifies the tracee's architecture according to m_syscall_info, throws on mismatch.
 
std::optional< SystemCallNrgetInitialSyscallNr (const ABI abi) const
 Returns the initial system call nr. stored in m_initial_regset, if available for abi.
 
void getInitialRegisters ()
 
void unshareProcessData ()
 
void doDetach ()
 Actually perform a detach without checking tracee state.
 
void handleError (const cosmos::ApiError &error)
 Handle ApiErrors raised from ptrace() requests.
 
bool hasClonedThread () const
 Returns whether the current/last seen system call was a clone() for a thread.
 
void trackFD (FDInfo &&info) const
 Track a new file descriptor for this Tracee's thread group.
 
void dropFD (const cosmos::FileNum fd) const
 Drop a file descriptor from the tracking of the Tracee's thread group.
 

Protected Attributes

cosmos::SubProc m_child
 the sub-process we're tracing
 
- Protected Attributes inherited from clues::Tracee
Enginem_engine
 The engine that manages this tracee.
 
EventConsumerm_consumer
 Callback interface receiving our information.
 
State m_state = State::UNKNOWN
 The current state the tracee is in.
 
State m_prev_state = State::UNKNOWN
 The previous Tracee state we've seen (except RUNNING).
 
Flags m_flags
 These keep track of various state on the tracer side.
 
cosmos::Tracee m_ptrace
 libcosmos API for the Tracee.
 
cosmos::ptrace::Opts m_ptrace_opts
 The options we've set for ptrace().
 
std::optional< SystemCallInfom_syscall_info
 The current system call information, if any.
 
SystemCallDB m_syscall_db
 Reusable database object for tracing system calls.
 
SystemCallm_current_syscall = nullptr
 Holds state for the currently executing system call.
 
SystemCallm_interrupted_syscall = nullptr
 Previous system call, if it has been interrupted.
 
cosmos::Tracee::RestartMode m_restart_mode = cosmos::Tracee::RestartMode::CONT
 current RestartMode to use.
 
std::optional< cosmos::Signal > m_inject_sig
 signal to inject upon next restart of the tracee.
 
std::optional< cosmos::ChildState > m_exit_data
 If tracee exit was observed then this contains the final exit data.
 
std::optional< cosmos::ProcessID > m_initial_attacher
 If this Tracee was automatically attached due to AttachThreads{true} then this contains the ProcessID of the initial Thread that caused this.
 
size_t m_syscall_ctr = 0
 Number of system calls observed.
 
AnyRegisterSet m_initial_regset
 Register set observed during initial attach event stop.
 
std::optional< cosmos::Signal > m_stop_signal
 For State::GROUP_STOP this contains the signal that caused it.
 
ProcessDataPtr m_process_data
 Shared process data.
 
size_t m_max_buffer_prefetch = 128
 Number of bytes system calls will fetch for variable-length data buffers.
 

Additional Inherited Members

- Public Types inherited from clues::Tracee
enum class  State {
  UNKNOWN , RUNNING , SYSCALL_ENTER_STOP , SYSCALL_EXIT_STOP ,
  SIGNAL_DELIVERY_STOP , GROUP_STOP , EVENT_STOP , DEAD ,
  DETACHED
}
 Current tracing state for a single tracee. More...
 
enum class  Flag {
  WAIT_FOR_ATTACH_STOP = 1 << 0 , DETACH_AT_NEXT_STOP = 1 << 1 , INJECTED_SIGSTOP = 1 << 2 , INJECTED_SIGCONT = 1 << 3 ,
  SYSCALL_ENTERED = 1 << 4 , WAIT_FOR_EXITED = 1 << 5 , ATTACH_THREADS_PENDING = 1 << 6 , SEEN_SIGRETURN = 1 << 7
}
 Different flags reflecting the tracer status. More...
 
using Flags = cosmos::BitMask<Flag>
 
- Static Public Member Functions inherited from clues::Tracee
static const char * getStateLabel (const State state)
 
- Static Protected Attributes inherited from clues::Tracee
static constexpr std::array< cosmos::Signal, 4 > STOPPING_SIGNALS
 Array of signals that cause tracee stop.
 

Detailed Description

Specialization of Tracee that creates a new child process for tracing.

Definition at line 12 of file ChildTracee.hxx.

Constructor & Destructor Documentation

◆ ChildTracee()

clues::ChildTracee::ChildTracee ( Engine & engine,
EventConsumer & consumer )

Create a traced process by creating a new process from prog_args

Definition at line 15 of file ChildTracee.cxx.

15 :
16 Tracee{engine, consumer} {
17}
Tracee(Engine &engine, EventConsumer &consumer, TraceePtr sibling=nullptr)
Definition Tracee.cxx:100

◆ ~ChildTracee()

clues::ChildTracee::~ChildTracee ( )
override

Definition at line 59 of file ChildTracee.cxx.

59 {
60 try {
61 if (m_child.running()) {
62 // make sure we can wait for it
63 try {
64 m_child.kill(cosmos::signal::KILL);
65 } catch( ... ) { }
66 }
67
68 cleanupChild();
69 } catch (const cosmos::CosmosError &ce) {
70 LOG_ERROR("Error detaching from child process PID "
71 << cosmos::to_integral(m_child.pid()) << ":\n\n"
72 << ce.what());
73 }
74}
cosmos::SubProc m_child
the sub-process we're tracing

Member Function Documentation

◆ cleanupChild()

void clues::ChildTracee::cleanupChild ( )
overrideprotectedvirtual

Reimplemented from clues::Tracee.

Definition at line 76 of file ChildTracee.cxx.

76 {
77
78 // this should actually only happen if a ChildTracee is detached
79 // explicitly and we're sending a SIGINT or something like that.
80 if (m_child.running()) {
81 try {
82 // the base class already stored the exit data
83 // this is just for keeping the SubProc state in sync.
84 (void)m_child.wait();
85 } catch (const cosmos::ApiError &error) {
86 if (error.errnum() != cosmos::Errno::NO_CHILD) {
87 // if it is ESRCH then just ignore it, the
88 // Engine already collected the result.
89 //
90 // this step is necessary to clean up the
91 // SubProc's internal state. Otherwise we'd
92 // need to use cosmos::proc::fork() to avoid
93 // using SubProc in the first place.
94 throw;
95 }
96 }
97 }
98}

◆ create()

void clues::ChildTracee::create ( const cosmos::StringVector & args)

Create the child process with the given parameters.

This only forks the process, but does not start executing the new program until attach() is called.

Definition at line 19 of file ChildTracee.cxx.

19 {
20 /*
21 * Here we have an issue with proper error reporting when the desired
22 * executable cannot be run. The execve() happens in child context and
23 * it is difficult to forward an error indication into parent context.
24 *
25 * ChildCloner offers a feature to forward execve() errors in the
26 * child synchronously to the parent. This doesn't work for our case,
27 * however, since we raise SIGSTOP in the child before executing,
28 * which would cause the `run()` call below to block forever, waiting
29 * for an execve() result.
30 *
31 * Using `fexecve()` would move typical file open errors to an earlier
32 * stage, but it has issues with scripts thats use the shebang to
33 * invoke an interpreter.
34 *
35 * It seems the only sensible thing to do is to check existence of the
36 * target path in a racy way beforehand.
37 */
38 if (args.empty() || !cosmos::fs::which(args[0])) {
39 changeState(State::DEAD);
40 throw cosmos::RuntimeError{
41 cosmos::sprintf("%s: does not exist or is not executable",
42 args.empty() ? "<empty-path>" : args[0].c_str())};
43 }
44
45 cosmos::ChildCloner cloner;
46 cloner.setArgs(args);
47 cloner.setPostForkCB([](const cosmos::ChildCloner &){
48 // this allows our parent to trace us before execve() happens
49 cosmos::signal::raise(cosmos::signal::STOP);
50 });
51 m_child = cloner.run();
52
53 m_child.wait(cosmos::WaitFlags{cosmos::WaitFlag::WAIT_FOR_STOPPED});
55
56 setPID(m_child.pid());
57}
void setPID(const cosmos::ProcessID tracee)
Sets the tracee PID.
Definition Tracee.cxx:129
@ INJECTED_SIGSTOP
whether we've injected a SIGSTOP that needs to be undone.
Definition Tracee.hxx:64
Flags m_flags
These keep track of various state on the tracer side.
Definition Tracee.hxx:442
@ DEAD
the tracee no longer exists.
Definition Tracee.hxx:56

◆ isChildProcess()

bool clues::ChildTracee::isChildProcess ( ) const
inlineoverrideprotectedvirtual

Returns whether the tracee is a child process created by us.

If the tracee is a child process then the tracer needs to take care of its lifecycle, while non-related tracee's can just be detached from.

Reimplemented from clues::Tracee.

Definition at line 30 of file ChildTracee.hxx.

30 {
31 return true;
32 }

Member Data Documentation

◆ m_child

cosmos::SubProc clues::ChildTracee::m_child
protected

the sub-process we're tracing

Definition at line 39 of file ChildTracee.hxx.


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