1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
|
#ifndef PARENT_H
#define PARENT_H
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <list>
#include <set>
#include <stdio.h>
#include <string>
#include <assert.h>
#include "arch/platform.h"
#include "platform_specific.h"
#include "refcount.h"
extern size_t static_mem_size, shared_mem_size;
bool attach_debugger( pid_t child );
class daemonProcess;
int process_children( daemonProcess *daemon );
int process_sigchld( pid_t pid, enum PTLIB_WAIT_RET wait_state, int status, long ret );
// Called whenever a new process is created
void handle_new_process( pid_t parent_id, pid_t child_id );
#define NUM_SAVED_STATES 5
struct pid_state {
/* The list of states a process can be in.
As far as the syscall handler is concerned, each state has a "before" and "after" semantics.
Before - between the point the process has sent us a SIGTRAP and the handler being called
After - between the handler's return and the process receiving a continue command
Handlers should check for the before state and should set the after state
Terminology:
Inbound - this is the SIGTRAP sent to us right before the kernel processes the syscall
Outbound - this is the SIGTRAP sent to us right after the kernel processed the syscall
*/
enum states {
INIT,
// Internal use - never set from a handler and will never be seen from a handler
NONE,
// Base state. Before - the process is inbound on a new syscall.
// After - process is outbound from the last syscall in this sequence.
RETURN,
// After - process is inbound to an unmodified syscall. Before - process is outbound from an unmodified syscall.
// The "unmodified" part is asserted by the main loop! Violating this constraint will crash the process in debug mode
REDIRECT1,
// After - Set in *Outbound* mode to indicate we initiated a new call with ptlib_generate_syscall
// Before - handled internally by process_sigchld - handler will never be called with this state
REDIRECT2,
// Before - outbound on a modified syscall. May or may not be a result of ptlib_generate_syscall
// After - Set when you want to change the original inbound syscall to something else.
// Do not use RETURN under those circumstances, as it will violate the assertion.
REDIRECT3,
// This mode rarely makes sense.
// After - handler generated a syscall, but would like to be notified when that syscall reaches inbound
// Before - inbound on generated syscall
ALLOCATE,
ALLOC_RETURN,
// The above two are used internally. The handler should never set them and will never see them set.
WAITING,
// After - the handler semantics needs to hold the process until some asynchronous operation is done.
// This state is somewhat special, as it is not tied to an outbound/inbound state.
// A handler setting this state should return false, to prevent process_sigchld from allowing the
// process to continue running.
// Before - the handler is called from "notify_parent", not "process_sigchld". Inbound/outbound depends on
//
// NOTICE: Release of a waiting process should not be done into the NONE state, as that would mean that if a recursive
// debugger is connected to the process, it will not see the syscall return!
ZOMBIE,
// As with real processes - the process has terminated, but has not yet been waited on.
} state;
int orig_sc; // Original system call
class process_memory {
int_ptr memory; // Where and how much mem do we have inside the process's address space
int_ptr shared_memory; // Process address of shared memory
void *shared_mem_local; // local pointers to the shared memory
size_t shared_overhead; // Size of the overhead the shared memory has
size_t shared_size; // Total size of mapping
// Disable the implicit constructors
process_memory( const process_memory &rhs );
process_memory &operator=( const process_memory &rhs );
public:
process_memory() : memory(0), shared_memory(0), shared_mem_local(MAP_FAILED), shared_overhead(0), shared_size(0)
{
}
~process_memory();
void set_local_addr(void *addr, size_t size, size_t overhead)
{
assert(shared_mem_local==MAP_FAILED);
if( addr!=MAP_FAILED && addr!=NULL ) {
shared_mem_local=(void *)(((int_ptr)addr)+overhead);
shared_overhead=overhead;
shared_size=size;
}
}
void set_remote_static(int_ptr addr)
{
assert(memory==0);
memory=addr;
}
void set_remote_shared(int_ptr addr)
{
shared_memory=addr;
}
// Accessors
void *get_loc() const
{
return shared_mem_local!=MAP_FAILED ? shared_mem_local : NULL;
}
char *get_loc_c() const
{
return (char *)get_loc();
}
int_ptr get_mem() const
{
return memory;
}
int_ptr get_shared() const
{
return shared_memory;
}
};
ref_count<process_memory> mem;
int_ptr context_state[NUM_SAVED_STATES];
void *saved_state[PTLIB_STATE_SIZE];
// "wait" simulation and recursive debuggers support
pid_t debugger, parent; // Which process thinks it's ptracing/parenting this one
int num_children, num_debugees; // How many child/debugged processes we have
int trace_mode; // Which ptrace mode was used to run the process
pid_t session_id;
ref_count<std::string> root;
// The credentials (including the Linux specific file system UID)
uid_t uid, euid, suid, fsuid;
gid_t gid, egid, sgid, fsgid;
std::set<gid_t> groups;
// Values for trace_mode
#define TRACE_DETACHED 0x0
#define TRACE_CONT 0x1
#define TRACE_SYSCALL 0x2
#define TRACE_SINGLSTEP 0x3
#define TRACE_MASK1 0x7
#define TRACE_STOPPED1 0x10
#define TRACE_STOPPED2 0x20
#define TRACE_MASK2 0x70
#define DEF_VAR(type, name) private: type _##name; \
public: type &name() { return _##name; } const type &name() const { return _##name; }
struct wait_state {
DEF_VAR( pid_t, pid)
DEF_VAR( int, status)
DEF_VAR( struct rusage, usage)
DEF_VAR( bool, debugonly) // Whether a parent that is not a debugger would have got this message
public:
wait_state() : _pid(0), _status(0), _debugonly(true)
{
}
wait_state( pid_t pid, int status, const struct rusage *usage, bool debugonly ) : _pid(pid), _status(status), _usage(*usage),
_debugonly(debugonly)
{
}
};
#undef DEF_VAR
std::list<wait_state> waiting_signals;
pid_state() : state(INIT), mem(ref_count<process_memory>(new process_memory)), debugger(0),
parent(0), num_children(0), num_debugees(0), trace_mode(TRACE_DETACHED), session_id(0), root(),
uid(ROOT_UID), euid(ROOT_UID), suid(ROOT_UID), fsuid(ROOT_UID), gid(ROOT_GID), egid(ROOT_GID), sgid(ROOT_GID), fsgid(ROOT_GID)
{
groups.insert(ROOT_GID);
}
};
// Look up a state by pid. Return NULL if the state does not exist
pid_state *lookup_state( pid_t pid );
// Delete a process. Must be called with state as ZOMBIE.
// Does reference counting, and will only perform actual delete when no more users.
void delete_state( pid_t pid );
// Dump all of the registered processes, including parent, state and zombie use count
void dump_states();
typedef bool (*sys_callback)( int sc_num, pid_t pid, pid_state *state );
struct syscall_hook {
sys_callback func;
const char *name;
syscall_hook() : func(NULL), name(NULL)
{
}
syscall_hook( sys_callback _func, const char *_name ) : func(_func), name(_name)
{
}
};
bool allocate_process_mem( pid_t pid, pid_state *state, int sc_num );
void dump_registers( pid_t pid );
#define PROC_MEM_LOCK()
#endif /* PARENT_H */
|