tnfctl_int.h revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1994, by Sun Microsytems, Inc.
*/
#ifndef _TNFCTL_INT_H
#define _TNFCTL_INT_H
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Interfaces private to libtnfctl
* layout of tnfctl handle structure
* layout of probe handle structure
* other misc. interfaces used across source files
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "tnfctl.h"
#include <sys/types.h>
#include <gelf.h>
#include <libelf.h>
#include "prb_proc.h"
/* for warlock (lock_lint) static lock checking */
#include <note.h>
#include <thread.h>
#include <synch.h>
/*
* This bogus structure is our way of getting around the fact that
* warlock does not handle recursive locks (warlock does not complain
* when anonymous locks, such as warlock_kludge->lmap_lock, are
* multiply locked).
*/
#if defined(__lock_lint)
struct warlock {
mutex_t lmap_lock;
} *warlock_kludge;
#endif
/*
* global variables used for INTERNAL_MODE synchronization with
* dlopen's and dlclose's on another thread.
*/
extern mutex_t _tnfctl_lmap_lock;
extern boolean_t _tnfctl_libs_changed;
NOTE(MUTEX_PROTECTS_DATA(warlock::lmap_lock, _tnfctl_libs_changed))
/* Project private interface - function name in target */
#define TRACE_END_FUNC "tnf_trace_end"
/* All tnfctl handles are in one of the following 4 modes */
enum proc_mode {
KERNEL_MODE, /* kernel tracing */
DIRECT_MODE, /* tracing another process (exec or attach) */
INDIRECT_MODE, /* client provides /proc functions */
INTERNAL_MODE /* tracing probes in the same process */
};
typedef struct prbctlref prbctlref_t;
typedef struct objlist objlist_t;
/* per probe state - transient - freed on dlclose() */
struct prbctlref {
uintptr_t addr; /* probe address in target */
objlist_t *obj; /* obj that this probe is in */
ulong_t probe_id; /* assigned id */
char *attr_string;
tnf_probe_control_t wrkprbctl; /* probe struct from target */
tnfctl_probe_t *probe_handle; /* handle visible to client */
};
NOTE(SCHEME_PROTECTS_DATA("one thread per handle", prbctlref))
NOTE(MUTEX_PROTECTS_DATA(warlock::lmap_lock, prbctlref::{addr obj}))
/* per object state */
struct objlist {
boolean_t new_probe; /* relative to last library change */
boolean_t new; /* relative to last sync with linker */
boolean_t old; /* relative to last sync with linker */
char * objname;
uintptr_t baseaddr;
int objfd;
uint_t min_probe_num; /* first probe id in object */
uint_t probecnt; /* number of probes in object */
prbctlref_t *probes; /* pointer to an array of probes */
objlist_t *next;
};
NOTE(SCHEME_PROTECTS_DATA("one thread per handle", objlist))
/* per probe state that is freed only on tnfctl_close() */
struct tnfctl_probe_handle {
boolean_t valid;
prbctlref_t *probe_p;
void *client_registered_data;
struct tnfctl_probe_handle *next;
};
NOTE(SCHEME_PROTECTS_DATA("one thread per handle", tnfctl_probe_handle))
/*
* state saved per tnfctl handle
*/
struct tnfctl_handle {
void *proc_p; /* proc handle */
int kfd; /* kernel handle */
pid_t targ_pid; /* pid of target */
enum proc_mode mode; /* mode of handle */
/* tracing info */
const char *trace_file_name;
int trace_buf_size;
int trace_min_size;
tnfctl_bufstate_t trace_buf_state;
boolean_t trace_state;
boolean_t kpidfilter_state;
boolean_t called_exit;
/* addresses of functions in target */
uintptr_t testfunc;
uintptr_t allocfunc;
uintptr_t commitfunc;
uintptr_t endfunc;
uintptr_t rollbackfunc;
uintptr_t probelist_head;
uintptr_t probelist_valid;
uintptr_t trace_error;
uintptr_t memseg_p;
uintptr_t nonthread_test;
uintptr_t thread_test;
uintptr_t thread_sync;
boolean_t mt_target;
uint_t num_probes; /* number of probes in target */
tnfctl_probe_t *probe_handle_list_head;
/* object info */
boolean_t in_objlist; /* _tnfctl_lmap_lock reentrancy check */
objlist_t *objlist;
/* combination info */
void *buildroot; /* root of built combinations */
void *decoderoot; /* root of decoded combinations */
/* per probe create/destroy functions */
void *(*create_func)(tnfctl_handle_t *, tnfctl_probe_t *);
void (*destroy_func)(void *);
/* functions to inspect target process */
int (*p_read)(void *prochandle, uintptr_t addr, void *buf, size_t size);
int (*p_write)(void *prochandle, uintptr_t addr,
void *buf, size_t size);
int (*p_obj_iter)(void *prochandle, tnfctl_ind_obj_f *func,
void *client_data);
pid_t (*p_getpid)(void *prochandle);
};
NOTE(SCHEME_PROTECTS_DATA("one thread per handle", tnfctl_handle))
NOTE(MUTEX_PROTECTS_DATA(warlock::lmap_lock, tnfctl_handle::objlist))
typedef enum comb_op {
PRB_COMB_CHAIN = 0, /* call the down, then the next */
PRB_COMB_COUNT = 1 /* how many? */
} comb_op_t;
enum event_op_t {
EVT_NONE,
EVT_OPEN,
EVT_CLOSE
};
/*
* interfaces to search for symbols or to search for relocations
* in an elf file
*/
typedef struct tnfctl_elf_search tnfctl_elf_search_t;
/* prototype for callback for traversing an elf section */
typedef tnfctl_errcode_t
(*tnfctl_traverse_section_func_t) (Elf * elf, char *strs, Elf_Scn * scn,
GElf_Shdr * shdr, Elf_Data * data, uintptr_t baseaddr,
tnfctl_elf_search_t * search_info);
/* prototype for callback for traversing records in an elf section */
typedef tnfctl_errcode_t
(*tnfctl_record_func_t) (char *name, uintptr_t addr, void *entry,
tnfctl_elf_search_t * search_info);
struct tnfctl_elf_search {
tnfctl_traverse_section_func_t section_func;
void *section_data;
tnfctl_record_func_t record_func;
void *record_data;
};
/* traverse all the sections in an object */
tnfctl_errcode_t _tnfctl_traverse_object(int objfd, uintptr_t addr,
tnfctl_elf_search_t *search_info_p);
/* search a .rela section */
tnfctl_errcode_t _tnfctl_traverse_rela(Elf * elf, char *strs, Elf_Scn * rel_scn,
GElf_Shdr * rel_shdr, Elf_Data * rel_data, uintptr_t baseaddr,
tnfctl_elf_search_t * search_info_p);
/* search a .dynsym section */
tnfctl_errcode_t _tnfctl_traverse_dynsym(Elf * elf, char *elfstrs,
Elf_Scn * scn, GElf_Shdr * shdr, Elf_Data * data, uintptr_t baseaddr,
tnfctl_elf_search_t * search_info_p);
/* prototype of callback for internal probe traversal function */
typedef tnfctl_errcode_t
(*_tnfctl_traverse_probe_func_t)(tnfctl_handle_t *, prbctlref_t *, void *);
/* sync up list of objects with that of the linker */
tnfctl_errcode_t _tnfctl_lmap_update(tnfctl_handle_t *hndl, boolean_t *lmap_ok,
enum event_op_t *evt);
/* sync up list of objects and probes */
tnfctl_errcode_t _tnfctl_refresh_process(tnfctl_handle_t *, boolean_t *,
enum event_op_t *);
tnfctl_errcode_t _tnfctl_set_state(tnfctl_handle_t *hndl);
tnfctl_errcode_t _tnfctl_create_tracefile(tnfctl_handle_t *hndl,
const char *trace_file_name, uint_t trace_file_size);
/* probe interfaces */
tnfctl_errcode_t _tnfctl_find_all_probes(tnfctl_handle_t *hndl);
tnfctl_errcode_t _tnfctl_probes_traverse(tnfctl_handle_t *hndl,
_tnfctl_traverse_probe_func_t func_p, void *calldata_p);
tnfctl_errcode_t _tnfctl_flush_a_probe(tnfctl_handle_t *hndl,
prbctlref_t *ref_p, size_t offset, size_t size);
/* combination interfaces */
tnfctl_errcode_t _tnfctl_comb_build(tnfctl_handle_t *hndl, comb_op_t op,
uintptr_t down, uintptr_t next, uintptr_t *comb_p);
tnfctl_errcode_t _tnfctl_comb_decode(tnfctl_handle_t *hndl, uintptr_t addr,
char ***func_names, uintptr_t **func_addrs);
/* allocate memory in target process */
tnfctl_errcode_t _tnfctl_targmem_alloc(tnfctl_handle_t *hndl, size_t size,
uintptr_t *addr_p);
/* inprocess "plug ins" for functions in tnfctl_handle_t structure */
int _tnfctl_read_targ(void *proc_p, uintptr_t addr, void *buf, size_t size);
int _tnfctl_write_targ(void *proc_p, uintptr_t addr, void *buf, size_t size);
int _tnfctl_loadobj_iter(void *proc_p, tnfctl_ind_obj_f *func,
void *client_data);
pid_t _tnfctl_pid_get(void *proc_p);
/* read a string from the target process */
tnfctl_errcode_t _tnfctl_readstr_targ(tnfctl_handle_t *hndl, uintptr_t addr,
char **outstr_pp);
/* symbol searching interfaces */
tnfctl_errcode_t _tnfctl_sym_find_in_obj(int objfd, uintptr_t baseaddr,
const char *symname, uintptr_t *symaddr);
tnfctl_errcode_t _tnfctl_sym_obj_find(tnfctl_handle_t *hndl,
const char *lib_base_name, const char *symname, uintptr_t *symaddr);
tnfctl_errcode_t _tnfctl_sym_find(tnfctl_handle_t *hndl, const char *symname,
uintptr_t *symaddr);
tnfctl_errcode_t _tnfctl_sym_findname(tnfctl_handle_t *hndl, uintptr_t symaddr,
char **symname);
tnfctl_errcode_t _tnfctl_elf_dbgent(tnfctl_handle_t *hndl,
uintptr_t * entaddr_p);
/* free objs and probes */
void _tnfctl_free_objs_and_probes(tnfctl_handle_t *);
/* locking interfaces */
tnfctl_errcode_t _tnfctl_lock_libs(tnfctl_handle_t *hndl,
boolean_t *release_lock);
void _tnfctl_unlock_libs(tnfctl_handle_t *hndl, boolean_t release_lock);
tnfctl_errcode_t _tnfctl_sync_lib_list(tnfctl_handle_t *hndl);
/*
* BugID 1253419
* The flags that indicate if in/external trace control is active.
* Used to prevent simultaneous internal and external probe control.
* For external control keep pid of traced process to handle case
* where process forks. (child is not under external control)
*/
#define TNFCTL_INTERNAL_TRACEFLAG "_tnfctl_internal_tracing_flag"
#define TNFCTL_EXTERNAL_TRACEDPID "_tnfctl_externally_traced_pid"
extern boolean_t _tnfctl_internal_tracing_flag;
extern pid_t _tnfctl_externally_traced_pid;
tnfctl_errcode_t _tnfctl_internal_getlock(void);
tnfctl_errcode_t _tnfctl_external_getlock(tnfctl_handle_t *hndl);
tnfctl_errcode_t _tnfctl_internal_releaselock(void);
tnfctl_errcode_t _tnfctl_external_releaselock(tnfctl_handle_t *hndl);
/* error mapping functions */
tnfctl_errcode_t _tnfctl_map_to_errcode(prb_status_t prbstat);
tnfctl_errcode_t tnfctl_status_map(int);
/*
* LOCK is the macro to lock down the library list so that a dlopen or
* dlclose by another thread will block waiting for the lock to be released.
*
* LOCK_SYNC does the same as LOCK + it syncs up libtnfctl's cache of
* libraries in target process with that of what the run time linker maintains.
*
* These macros do conditional locking because they are needed only by
* INTERNAL_MODE clients. There are 2 versions of these macros so that
* lock_lint won't have to see the conditional locking.
* CAUTION: Be aware that these macros have a return() embedded in them.
*/
#ifdef __lock_lint
#define LOCK(hndl, stat, release) (void) _tnfctl_lock_libs(hndl, &release)
#define LOCK_SYNC(hndl, stat, release) \
(void) _tnfctl_lock_libs(hndl, &release); \
(void) _tnfctl_sync_lib_list(hndl)
#define UNLOCK(hndl, release) _tnfctl_unlock_libs(hndl, release)
#else
#define LOCK(hndl, stat, release) \
if (hndl->mode == INTERNAL_MODE) { \
stat = _tnfctl_lock_libs(hndl, &release); \
if (stat) \
return (stat); \
} \
else
#define LOCK_SYNC(hndl, stat, release) \
if (hndl->mode == INTERNAL_MODE) { \
stat = _tnfctl_lock_libs(hndl, &release); \
if (stat) \
return (stat); \
stat = _tnfctl_sync_lib_list(hndl); \
if (stat) { \
_tnfctl_unlock_libs(hndl, release); \
return (stat); \
} \
} \
else
#define UNLOCK(hndl, release) \
if (hndl->mode == INTERNAL_MODE) \
_tnfctl_unlock_libs(hndl, release_lock); \
else
#endif
#ifdef __cplusplus
}
#endif
#endif /* _TNFCTL_INT_H */