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 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
|
/*
* Oracle Linux DTrace.
* Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
/*
* Portions Copyright 2007 Chad Mynhier
*/
/*
* Interfaces available from the process control library, libproc.
*/
#ifndef _LIBPROC_H
#define _LIBPROC_H
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <setjmp.h>
#include <gelf.h>
#include <sys/statvfs.h>
#include <sys/wait.h>
#include <rtld_db.h>
#include <sys/ctf-api.h>
#include <sys/ptrace.h>
#include <sys/sol_procfs.h>
#include <sys/dtrace_types.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/compiler.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* Maximum number of digits needed for a pid so we can properly
* size strings for /proc/$pid/auxv, /proc/$pid/maps, etc.
* E.g., if procname[] will be "$procfs/$pid/exe", we size
* char procname[PATH_MAX + MAXLEN_PID + strlen("/exe") + 1];
* The null-terminating char of $procfs is overwritten by a '/',
* and then we add space for the new terminating char at the end.
*/
#define MAXLEN_PID 9
/*
* Opaque structure tag reference to a process control structure.
* Clients of libproc cannot look inside the process control structure.
* The implementation of struct ps_prochandle can change w/o affecting clients.
*/
struct ps_prochandle;
typedef struct ps_prochandle ps_prochandle;
/* State values returned by Pstate() */
#define PS_RUN 1 /* process is running */
#define PS_STOP 2 /* process is stopped by SIGSTOP etc */
#define PS_TRACESTOP 3 /* process is stopped by ptrace() or bkpts */
#define PS_DEAD 4 /* process is terminated (core file) */
/* Values for Prelease()'s release_mode argument */
#define PS_RELEASE_NORMAL 0 /* ptrace detach, do not kill */
#define PS_RELEASE_KILL 1 /* ptrace detach and kill */
#define PS_RELEASE_NO_DETACH 2 /* no ptrace detach or lock release */
/*
* Function prototypes for routines in the process control package.
*/
extern struct ps_prochandle *Pcreate(const char *, char *const *,
void *, int *);
extern struct ps_prochandle *Pgrab(pid_t pid, int noninvasiveness,
int already_ptraced, void *wrap_arg, int *perr);
extern int Ptrace(struct ps_prochandle *, int stopped);
extern void Ptrace_set_detached(struct ps_prochandle *, boolean_t);
extern void Prelease(struct ps_prochandle *, int);
extern void Pfree(struct ps_prochandle *P);
extern void Puntrace(struct ps_prochandle *, int stay_stopped);
extern void Pclose(struct ps_prochandle *);
extern int Pmemfd(struct ps_prochandle *);
extern long Pwait(struct ps_prochandle *, boolean_t block,
int *return_early);
extern int Pstate(struct ps_prochandle *);
extern ssize_t Pread(struct ps_prochandle *, void *, size_t, uintptr_t);
extern ssize_t Pread_string(struct ps_prochandle *, char *, size_t, uintptr_t);
extern ssize_t Pread_scalar(struct ps_prochandle *P, void *buf, size_t nbyte,
size_t nscalar, uintptr_t address);
extern ssize_t Pread_scalar_quietly(struct ps_prochandle *P, void *buf,
size_t nbyte, size_t nscalar, uintptr_t address, int quietly);
extern int Phasfds(struct ps_prochandle *);
extern void Pset_procfs_path(const char *);
extern int Pdynamically_linked(struct ps_prochandle *);
extern int Ptraceable(struct ps_prochandle *);
extern int Pelf64(struct ps_prochandle *);
extern pid_t Ptracer_pid(pid_t);
extern pid_t Ptgid(pid_t);
/*
* Calls that do not take a process structure. These are used to determine
* whether it is sensible to grab a pid at all, before the grab takes place.
*/
extern int Pexists(pid_t pid);
extern int Psystem_daemon(pid_t pid, uid_t useruid, const char *sysslice);
/*
* Read the first argument of the function at which the process P is
* halted, which must be a pointer.
*
* On error, -1 cast to a uintptr_t is returned, and errno is set.
*/
extern uintptr_t Pread_first_arg(struct ps_prochandle *P);
/*
* Hook and wrapper functions. These functions all get their 'arg' argument
* from the corresponding argument to Pcreate() and Pgrab().
*
* Route all calls to ptrace() via the specified wrapper function.
*
* _arg_ is constant for all calls using this prochandle until the next call to
* Pset_ptrace_wrapper().
*/
typedef long ptrace_fun(enum __ptrace_request request, void *arg, pid_t pid,
void *addr, void *data);
extern void Pset_ptrace_wrapper(struct ps_prochandle *P,
ptrace_fun *wrapper);
/*
* Likewise, but for Pwait().
*
* A program intending to call libproc functions from threads other than those
* grabbing the process will typically need to wrap both ptrace() and Pwait().
*/
typedef long pwait_fun(struct ps_prochandle *P, void *arg, boolean_t block,
int *return_early);
extern void Pset_pwait_wrapper(struct ps_prochandle *P, pwait_fun *wrapper);
/*
* The function that implements the guts of Pwait(), that the Pwait() wrapper
* function should end up calling (somehow, from some thread or other). Safe to
* call only from the thread that did Pgrab() or Pcreate().
*/
extern long Pwait_internal(struct ps_prochandle *P, boolean_t block,
int *return_early);
/*
* Register a function to be called around the outermost layer of Ptrace()/
* Puntrace() calls. This can, e.g., take a mutex to ensure that other threads
* do not interfere and unbalance the Ptrace()/Puntrace() stack by issuing
* further Ptrace()/Puntrace() calls while inside at least one Ptrace().
*
* Note that on exit from Pgrab()/Pcreate(), we are in a Ptrace(), so the lock
* will be taken out then.
*
* This locking function is *global* and applies to all libproc calls, but P and
* the arg are not global.
*/
typedef void ptrace_lock_hook_fun(struct ps_prochandle *P, void *arg,
int ptracing);
extern void Pset_ptrace_lock_hook(ptrace_lock_hook_fun *hook);
/*
* Like the ptrace_lock_hook, but of inverse sign: used to possibly release
* locks around long-running blocking waitpid() calls inside Pwait(), while
* retaining the lock for the remainder of Pwait() (which may trigger
* breakpoints, invoke other wrapped functions etc).
*/
typedef void waitpid_lock_hook_fun(struct ps_prochandle *P, void *arg,
int waitpidding);
extern void Pset_waitpid_lock_hook(waitpid_lock_hook_fun *hook);
/*
* Register a function that returns the address of a per-thread pointer-sized
* area suitable for storing a jmp_buf, to be called on exec() to register a
* chain of setjmp loci to unwind out of libproc. Must never return NULL (but
* can return a pointer to NULL to indicate that no rethrowing is needed at this
* point, even if an exec() is detected).
*
* As with the ptrace lock hook, this is global, for the same reason (it must
* work during Pcreate() and Pgrab()).
*/
typedef jmp_buf **libproc_unwinder_pad_fun(struct ps_prochandle *P);
extern void Pset_libproc_unwinder_pad(libproc_unwinder_pad_fun *unwinder_pad);
/*
* Breakpoints.
*
* This is not a completely safe interface: it cannot handle breakpoints on
* signal return.
*/
extern int Pbkpt(struct ps_prochandle *P, uintptr_t addr, int after_singlestep,
int (*bkpt_handler)(uintptr_t addr, void *data),
void (*bkpt_cleanup)(void *data),
void *data);
extern int Pbkpt_notifier(struct ps_prochandle *P, uintptr_t addr, int after_singlestep,
void (*bkpt_handler)(uintptr_t addr, void *data),
void (*bkpt_cleanup)(void *data),
void *data);
extern void Punbkpt(struct ps_prochandle *P, uintptr_t address);
extern int Pbkpt_continue(struct ps_prochandle *P);
extern uintptr_t Pbkpt_addr(struct ps_prochandle *P);
/*
* Symbol table interfaces.
*/
/*
* Pseudo-names passed to Plookup_by_name() for well-known load objects.
*/
#define PR_OBJ_EXEC ((const char *)0) /* search the executable file */
#define PR_OBJ_LDSO ((const char *)1) /* search ld.so */
#define PR_OBJ_EVERY ((const char *)-1) /* search every load object */
/*
* Special Lmid_t passed to Plookup_by_lmid() to search all link maps. The
* special values LM_ID_BASE and LM_ID_LDSO from <link.h> may also be used.
* If PR_OBJ_EXEC is used as the object name, the lmid must be PR_LMID_EVERY
* or LM_ID_BASE in order to return a match. If PR_OBJ_LDSO is used as the
* object name, the lmid must be PR_LMID_EVERY or LM_ID_LDSO to return a match.
*/
#define PR_LMID_EVERY ((Lmid_t)-1UL) /* search every link map */
/*
* 'object_name' is the name of a load object obtained from an
* an iteration over the process's mapped objects (Pobject_iter),
* or else it is one of the special PR_OBJ_* values above.
*/
extern int Plookup_by_addr(struct ps_prochandle *, uintptr_t, const char **,
GElf_Sym *);
typedef struct prsyminfo {
const char *prs_object; /* object name */
const char *prs_name; /* symbol name */
Lmid_t prs_lmid; /* link map id */
uint_t prs_id; /* symbol id */
uint_t prs_table; /* symbol table id */
} prsyminfo_t;
extern int Pxlookup_by_name(struct ps_prochandle *,
Lmid_t, const char *, const char *, GElf_Sym *, prsyminfo_t *);
typedef int proc_map_f(void *, const prmap_t *, const char *);
extern int Pobject_iter(struct ps_prochandle *, proc_map_f *, void *);
extern const prmap_t *Paddr_to_map(struct ps_prochandle *, uintptr_t);
extern const prmap_t *Pname_to_map(struct ps_prochandle *, const char *);
extern const prmap_t *Plmid_to_map(struct ps_prochandle *,
Lmid_t, const char *);
extern const prmap_file_t *Pinode_to_file_map(struct ps_prochandle *,
dev_t, ino_t);
extern char *Pmap_mapfile_name(struct ps_prochandle *P, const prmap_t *mapp);
extern char *Pobjname(struct ps_prochandle *, uintptr_t, char *, size_t);
extern int Plmid(struct ps_prochandle *, uintptr_t, Lmid_t *);
extern uint64_t Pgetauxval(struct ps_prochandle *P, int type);
/*
* Symbol table iteration interface.
*/
typedef int proc_sym_f(void *, const GElf_Sym *, const char *);
extern int Psymbol_iter_by_addr(struct ps_prochandle *,
const char *, int, int, proc_sym_f *, void *);
/*
* 'which' selects which symbol table and can be one of the following.
*/
#define PR_SYMTAB 1
#define PR_DYNSYM 2
/*
* 'type' selects the symbols of interest by binding and type. It is a bit-
* mask of one or more of the following flags, whose order MUST match the
* order of STB and STT constants in <sys/elf.h>.
*/
#define BIND_LOCAL 0x0001
#define BIND_GLOBAL 0x0002
#define BIND_WEAK 0x0004
#define BIND_ANY (BIND_LOCAL|BIND_GLOBAL|BIND_WEAK)
#define TYPE_NOTYPE 0x0100
#define TYPE_OBJECT 0x0200
#define TYPE_FUNC 0x0400
#define TYPE_SECTION 0x0800
#define TYPE_FILE 0x1000
#define TYPE_ANY (TYPE_NOTYPE|TYPE_OBJECT|TYPE_FUNC|TYPE_SECTION|TYPE_FILE)
/*
* This should be called when an RD_DLACTIVITY event with the
* RD_CONSISTENT state occurs via librtld_db's event mechanism.
* This makes libproc's address space mappings and symbol tables current.
* The variant Pupdate_syms() can be used to preload all symbol tables as well.
*/
extern void Pupdate_maps(struct ps_prochandle *);
extern void Pupdate_syms(struct ps_prochandle *);
/*
* This must be called after the victim process performs a successful
* exec() if any of the symbol table interface functions have been called
* prior to that point. This is essential because an exec() invalidates
* all previous symbol table and address space mapping information.
* It is always safe to call, but if it is called other than after an
* exec() by the victim process it just causes unnecessary overhead.
*
* The rtld_db agent handle obtained from a previous call to Prd_agent() is
* made invalid by Preset_maps() and Prd_agent() must be called again to get
* the new handle.
*/
extern void Preset_maps(struct ps_prochandle *);
/*
* Return 1 if this address is within a valid mapping, file-backed mapping, or
* writable mapping, respectively.
*/
extern int Pvalid_mapping(struct ps_prochandle *P, uintptr_t addr);
extern int Pfile_mapping(struct ps_prochandle *P, uintptr_t addr);
extern int Pwritable_mapping(struct ps_prochandle *P, uintptr_t addr);
extern pid_t Pgetpid(struct ps_prochandle *);
/*
* Return the librtld_db agent handle for the victim process.
* The handle will become invalid at the next successful exec() and the
* client (caller of proc_rd_agent()) must not use it beyond that point.
* If the process is already dead, there's nothing we can do.
*/
rd_agent_t *Prd_agent(struct ps_prochandle *);
#ifdef __cplusplus
}
#endif
#endif /* _LIBPROC_H */
|