diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h index b3f69bb6329d..1e62bd6b21db 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h @@ -1,756 +1,757 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2011, 2016 by Delphix. All rights reserved. */ #ifndef _DT_IMPL_H #define _DT_IMPL_H #include #include #ifndef illumos #include #include #include #include #include #endif #include #include #include #include #ifdef illumos #include #endif #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include #include #include #include #include #include struct dt_module; /* see below */ struct dt_pfdict; /* see */ struct dt_arg; /* see below */ struct dt_provider; /* see */ struct dt_xlator; /* see */ typedef struct dt_intrinsic { const char *din_name; /* string name of the intrinsic type */ ctf_encoding_t din_data; /* integer or floating-point CTF encoding */ uint_t din_kind; /* CTF type kind to instantiate */ } dt_intrinsic_t; typedef struct dt_typedef { const char *dty_src; /* string name of typedef source type */ const char *dty_dst; /* string name of typedef destination type */ } dt_typedef_t; typedef struct dt_intdesc { const char *did_name; /* string name of the integer type */ ctf_file_t *did_ctfp; /* CTF container for this type reference */ ctf_id_t did_type; /* CTF type reference for this type */ uintmax_t did_limit; /* maximum positive value held by type */ } dt_intdesc_t; typedef struct dt_modops { uint_t (*do_syminit)(struct dt_module *); void (*do_symsort)(struct dt_module *); GElf_Sym *(*do_symname)(struct dt_module *, const char *, GElf_Sym *, uint_t *); GElf_Sym *(*do_symaddr)(struct dt_module *, GElf_Addr, GElf_Sym *, uint_t *); } dt_modops_t; typedef struct dt_arg { int da_ndx; /* index of this argument */ int da_mapping; /* mapping of argument indices to arguments */ ctf_id_t da_type; /* type of argument */ ctf_file_t *da_ctfp; /* CTF container for type */ dt_ident_t *da_xlator; /* translator, if any */ struct dt_arg *da_next; /* next argument */ } dt_arg_t; typedef struct dt_sym { uint_t ds_symid; /* id of corresponding symbol */ uint_t ds_next; /* index of next element in hash chain */ } dt_sym_t; typedef struct dt_module { dt_list_t dm_list; /* list forward/back pointers */ char dm_name[DTRACE_MODNAMELEN]; /* string name of module */ char dm_file[MAXPATHLEN]; /* file path of module (if any) */ struct dt_module *dm_next; /* pointer to next module in hash chain */ const dt_modops_t *dm_ops; /* pointer to data model's ops vector */ Elf *dm_elf; /* libelf handle for module object */ objfs_info_t dm_info; /* object filesystem private info */ ctf_sect_t dm_symtab; /* symbol table for module */ ctf_sect_t dm_strtab; /* string table for module */ ctf_sect_t dm_ctdata; /* CTF data for module */ ctf_file_t *dm_ctfp; /* CTF container handle */ uint_t *dm_symbuckets; /* symbol table hash buckets (chain indices) */ dt_sym_t *dm_symchains; /* symbol table hash chains buffer */ void *dm_asmap; /* symbol pointers sorted by value */ uint_t dm_symfree; /* index of next free hash element */ uint_t dm_nsymbuckets; /* number of elements in bucket array */ uint_t dm_nsymelems; /* number of elements in hash table */ uint_t dm_asrsv; /* actual reserved size of dm_asmap */ uint_t dm_aslen; /* number of entries in dm_asmap */ uint_t dm_flags; /* module flags (see below) */ int dm_modid; /* modinfo(1M) module identifier */ GElf_Addr dm_text_va; /* virtual address of text section */ GElf_Xword dm_text_size; /* size in bytes of text section */ GElf_Addr dm_data_va; /* virtual address of data section */ GElf_Xword dm_data_size; /* size in bytes of data section */ GElf_Addr dm_bss_va; /* virtual address of BSS */ GElf_Xword dm_bss_size; /* size in bytes of BSS */ dt_idhash_t *dm_extern; /* external symbol definitions */ #ifndef illumos caddr_t dm_reloc_offset; /* Symbol relocation offset. */ uintptr_t *dm_sec_offsets; #endif pid_t dm_pid; /* pid for this module */ uint_t dm_nctflibs; /* number of ctf children libraries */ ctf_file_t **dm_libctfp; /* process library ctf pointers */ char **dm_libctfn; /* names of process ctf containers */ } dt_module_t; #define DT_DM_LOADED 0x1 /* module symbol and type data is loaded */ #define DT_DM_KERNEL 0x2 /* module is associated with a kernel object */ #define DT_DM_PRIMARY 0x4 /* module is a krtld primary kernel object */ #ifdef __FreeBSD__ /* * A representation of a FreeBSD kernel module, used when checking module * dependencies. This differs from dt_module_t, which refers to a KLD in the * case of kernel probes. Since modules can be identified regardless of whether * they've been compiled into the kernel, we use them to identify DTrace * modules. */ typedef struct dt_kmodule { struct dt_kmodule *dkm_next; /* hash table entry */ char *dkm_name; /* string name of module */ dt_module_t *dkm_module; /* corresponding KLD module */ } dt_kmodule_t; #endif typedef struct dt_provmod { char *dp_name; /* name of provider module */ struct dt_provmod *dp_next; /* next module */ } dt_provmod_t; typedef struct dt_ahashent { struct dt_ahashent *dtahe_prev; /* prev on hash chain */ struct dt_ahashent *dtahe_next; /* next on hash chain */ struct dt_ahashent *dtahe_prevall; /* prev on list of all */ struct dt_ahashent *dtahe_nextall; /* next on list of all */ uint64_t dtahe_hashval; /* hash value */ size_t dtahe_size; /* size of data */ dtrace_aggdata_t dtahe_data; /* data */ void (*dtahe_aggregate)(int64_t *, int64_t *, size_t); /* function */ } dt_ahashent_t; typedef struct dt_ahash { dt_ahashent_t **dtah_hash; /* hash table */ dt_ahashent_t *dtah_all; /* list of all elements */ size_t dtah_size; /* size of hash table */ } dt_ahash_t; typedef struct dt_aggregate { dtrace_bufdesc_t dtat_buf; /* buf aggregation snapshot */ int dtat_flags; /* aggregate flags */ processorid_t dtat_ncpus; /* number of CPUs in aggregate */ processorid_t *dtat_cpus; /* CPUs in aggregate */ processorid_t dtat_ncpu; /* size of dtat_cpus array */ processorid_t dtat_maxcpu; /* maximum number of CPUs */ dt_ahash_t dtat_hash; /* aggregate hash table */ } dt_aggregate_t; typedef struct dt_print_aggdata { dtrace_hdl_t *dtpa_dtp; /* pointer to libdtrace handle */ dtrace_aggvarid_t dtpa_id; /* aggregation variable of interest */ FILE *dtpa_fp; /* file pointer */ int dtpa_allunprint; /* print only unprinted aggregations */ int dtpa_agghist; /* print aggregation as histogram */ int dtpa_agghisthdr; /* aggregation histogram hdr printed */ int dtpa_aggpack; /* pack quantized aggregations */ } dt_print_aggdata_t; typedef struct dt_dirpath { dt_list_t dir_list; /* linked-list forward/back pointers */ char *dir_path; /* directory pathname */ } dt_dirpath_t; typedef struct dt_lib_depend { dt_list_t dtld_deplist; /* linked-list forward/back pointers */ char *dtld_library; /* library name */ char *dtld_libpath; /* library pathname */ uint_t dtld_finish; /* completion time in tsort for lib */ uint_t dtld_start; /* starting time in tsort for lib */ uint_t dtld_loaded; /* boolean: is this library loaded */ dt_list_t dtld_dependencies; /* linked-list of lib dependencies */ dt_list_t dtld_dependents; /* linked-list of lib dependents */ } dt_lib_depend_t; typedef uint32_t dt_version_t; /* encoded version (see below) */ struct dtrace_hdl { const dtrace_vector_t *dt_vector; /* library vector, if vectored open */ void *dt_varg; /* vector argument, if vectored open */ dtrace_conf_t dt_conf; /* DTrace driver configuration profile */ char dt_errmsg[BUFSIZ]; /* buffer for formatted syntax error msgs */ const char *dt_errtag; /* tag used with last call to dt_set_errmsg() */ dt_pcb_t *dt_pcb; /* pointer to current parsing control block */ ulong_t dt_gen; /* compiler generation number */ dt_list_t dt_programs; /* linked list of dtrace_prog_t's */ dt_list_t dt_xlators; /* linked list of dt_xlator_t's */ struct dt_xlator **dt_xlatormap; /* dt_xlator_t's indexed by dx_id */ id_t dt_xlatorid; /* next dt_xlator_t id to assign */ dt_ident_t *dt_externs; /* linked list of external symbol identifiers */ dt_idhash_t *dt_macros; /* hash table of macro variable identifiers */ dt_idhash_t *dt_aggs; /* hash table of aggregation identifiers */ dt_idhash_t *dt_globals; /* hash table of global identifiers */ dt_idhash_t *dt_tls; /* hash table of thread-local identifiers */ dt_list_t dt_modlist; /* linked list of dt_module_t's */ dt_module_t **dt_mods; /* hash table of dt_module_t's */ #ifdef __FreeBSD__ dt_kmodule_t **dt_kmods; /* hash table of dt_kmodule_t's */ #endif uint_t dt_modbuckets; /* number of module hash buckets */ uint_t dt_nmods; /* number of modules in hash and list */ dt_provmod_t *dt_provmod; /* linked list of provider modules */ dt_module_t *dt_exec; /* pointer to executable module */ dt_module_t *dt_rtld; /* pointer to run-time linker module */ dt_module_t *dt_cdefs; /* pointer to C dynamic type module */ dt_module_t *dt_ddefs; /* pointer to D dynamic type module */ dt_list_t dt_provlist; /* linked list of dt_provider_t's */ struct dt_provider **dt_provs; /* hash table of dt_provider_t's */ uint_t dt_provbuckets; /* number of provider hash buckets */ uint_t dt_nprovs; /* number of providers in hash and list */ dt_proc_hash_t *dt_procs; /* hash table of grabbed process handles */ char **dt_proc_env; /* additional environment variables */ dt_intdesc_t dt_ints[6]; /* cached integer type descriptions */ ctf_id_t dt_type_func; /* cached CTF identifier for function type */ ctf_id_t dt_type_fptr; /* cached CTF identifier for function pointer */ ctf_id_t dt_type_str; /* cached CTF identifier for string type */ ctf_id_t dt_type_dyn; /* cached CTF identifier for type */ ctf_id_t dt_type_stack; /* cached CTF identifier for stack type */ ctf_id_t dt_type_symaddr; /* cached CTF identifier for _symaddr type */ ctf_id_t dt_type_usymaddr; /* cached CTF ident. for _usymaddr type */ size_t dt_maxprobe; /* max enabled probe ID */ dtrace_eprobedesc_t **dt_edesc; /* enabled probe descriptions */ dtrace_probedesc_t **dt_pdesc; /* probe descriptions for enabled prbs */ size_t dt_maxagg; /* max aggregation ID */ dtrace_aggdesc_t **dt_aggdesc; /* aggregation descriptions */ int dt_maxformat; /* max format ID */ void **dt_formats; /* pointer to format array */ int dt_maxstrdata; /* max strdata ID */ char **dt_strdata; /* pointer to strdata array */ dt_aggregate_t dt_aggregate; /* aggregate */ dt_pq_t *dt_bufq; /* CPU-specific data queue */ struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */ dt_version_t dt_vmax; /* optional ceiling on program API binding */ dtrace_attribute_t dt_amin; /* optional floor on program attributes */ char *dt_cpp_path; /* pathname of cpp(1) to invoke if needed */ char **dt_cpp_argv; /* argument vector for exec'ing cpp(1) */ int dt_cpp_argc; /* count of initialized cpp(1) arguments */ int dt_cpp_args; /* size of dt_cpp_argv[] array */ char *dt_ld_path; /* pathname of ld(1) to invoke if needed */ #ifdef __FreeBSD__ char *dt_objcopy_path; /* pathname of objcopy(1) to invoke if needed */ #endif dt_list_t dt_lib_path; /* linked-list forming library search path */ uint_t dt_lazyload; /* boolean: set via -xlazyload */ uint_t dt_droptags; /* boolean: set via -xdroptags */ uint_t dt_active; /* boolean: set once tracing is active */ uint_t dt_stopped; /* boolean: set once tracing is stopped */ processorid_t dt_beganon; /* CPU that executed BEGIN probe (if any) */ processorid_t dt_endedon; /* CPU that executed END probe (if any) */ uint_t dt_oflags; /* dtrace open-time options (see dtrace.h) */ uint_t dt_cflags; /* dtrace compile-time options (see dtrace.h) */ uint_t dt_dflags; /* dtrace link-time options (see dtrace.h) */ uint_t dt_prcmode; /* dtrace process create mode (see dt_proc.h) */ uint_t dt_linkmode; /* dtrace symbol linking mode (see below) */ uint_t dt_linktype; /* dtrace link output file type (see below) */ uint_t dt_xlatemode; /* dtrace translator linking mode (see below) */ uint_t dt_stdcmode; /* dtrace stdc compatibility mode (see below) */ uint_t dt_encoding; /* dtrace output encoding (see below) */ uint_t dt_treedump; /* dtrace tree debug bitmap (see below) */ uint64_t dt_options[DTRACEOPT_MAX]; /* dtrace run-time options */ int dt_version; /* library version requested by client */ int dt_ctferr; /* error resulting from last CTF failure */ int dt_errno; /* error resulting from last failed operation */ #ifndef illumos const char *dt_errfile; int dt_errline; #endif int dt_fd; /* file descriptor for dtrace pseudo-device */ int dt_ftfd; /* file descriptor for fasttrap pseudo-device */ + int dt_kinstfd; /* file descriptor for kinst pseudo-device */ int dt_fterr; /* saved errno from failed open of dt_ftfd */ int dt_cdefs_fd; /* file descriptor for C CTF debugging cache */ int dt_ddefs_fd; /* file descriptor for D CTF debugging cache */ #ifdef illumos int dt_stdout_fd; /* file descriptor for saved stdout */ #else FILE *dt_freopen_fp; /* file pointer for freopened stdout */ #endif dtrace_handle_err_f *dt_errhdlr; /* error handler, if any */ void *dt_errarg; /* error handler argument */ dtrace_prog_t *dt_errprog; /* error handler program, if any */ dtrace_handle_drop_f *dt_drophdlr; /* drop handler, if any */ void *dt_droparg; /* drop handler argument */ dtrace_handle_proc_f *dt_prochdlr; /* proc handler, if any */ void *dt_procarg; /* proc handler argument */ dtrace_handle_setopt_f *dt_setopthdlr; /* setopt handler, if any */ void *dt_setoptarg; /* setopt handler argument */ dtrace_status_t dt_status[2]; /* status cache */ int dt_statusgen; /* current status generation */ hrtime_t dt_laststatus; /* last status */ hrtime_t dt_lastswitch; /* last switch of buffer data */ hrtime_t dt_lastagg; /* last snapshot of aggregation data */ char *dt_sprintf_buf; /* buffer for dtrace_sprintf() */ int dt_sprintf_buflen; /* length of dtrace_sprintf() buffer */ const char *dt_filetag; /* default filetag for dt_set_errmsg() */ char *dt_buffered_buf; /* buffer for buffered output */ size_t dt_buffered_offs; /* current offset into buffered buffer */ size_t dt_buffered_size; /* size of buffered buffer */ dtrace_handle_buffered_f *dt_bufhdlr; /* buffered handler, if any */ void *dt_bufarg; /* buffered handler argument */ dt_dof_t dt_dof; /* DOF generation buffers (see dt_dof.c) */ struct utsname dt_uts; /* uname(2) information for system */ dt_list_t dt_lib_dep; /* scratch linked-list of lib dependencies */ dt_list_t dt_lib_dep_sorted; /* dependency sorted library list */ dtrace_flowkind_t dt_flow; /* flow kind */ const char *dt_prefix; /* recommended flow prefix */ int dt_indent; /* recommended flow indent */ dtrace_epid_t dt_last_epid; /* most recently consumed EPID */ uint64_t dt_last_timestamp; /* most recently consumed timestamp */ boolean_t dt_has_sugar; /* syntactic sugar used? */ }; /* * Values for the user arg of the ECB. */ #define DT_ECB_DEFAULT 0 #define DT_ECB_ERROR 1 /* * Values for the dt_linkmode property, which is used by the assembler when * processing external symbol references. User can set using -xlink=. */ #define DT_LINK_KERNEL 0 /* kernel syms static, user syms dynamic */ #define DT_LINK_PRIMARY 1 /* primary kernel syms static, others dynamic */ #define DT_LINK_DYNAMIC 2 /* all symbols dynamic */ #define DT_LINK_STATIC 3 /* all symbols static */ /* * Values for the dt_linktype property, which is used by dtrace_program_link() * to determine the type of output file that is desired by the client. */ #define DT_LTYP_ELF 0 /* produce ELF containing DOF */ #define DT_LTYP_DOF 1 /* produce stand-alone DOF */ /* * Values for the dt_xlatemode property, which is used to determine whether * references to dynamic translators are permitted. Set using -xlate=. */ #define DT_XL_STATIC 0 /* require xlators to be statically defined */ #define DT_XL_DYNAMIC 1 /* produce references to dynamic translators */ /* * Values for the dt_stdcmode property, which is used by the compiler when * running cpp to determine the presence and setting of the __STDC__ macro. */ #define DT_STDC_XA 0 /* ISO C + K&R C compat w/o ISO: __STDC__=0 */ #define DT_STDC_XC 1 /* Strict ISO C: __STDC__=1 */ #define DT_STDC_XS 2 /* K&R C: __STDC__ not defined */ #define DT_STDC_XT 3 /* ISO C + K&R C compat with ISO: __STDC__=0 */ /* * Values for the dt_encoding property, which is used to force a particular * character encoding (overriding default behavior and/or automatic detection). */ #define DT_ENCODING_UNSET 0 #define DT_ENCODING_ASCII 1 #define DT_ENCODING_UTF8 2 /* * Macro to test whether a given pass bit is set in the dt_treedump bit-vector. * If the bit for pass 'p' is set, the D compiler displays the parse tree for * the program by printing it to stderr at the end of compiler pass 'p'. */ #define DT_TREEDUMP_PASS(dtp, p) ((dtp)->dt_treedump & (1 << ((p) - 1))) /* * Macros for accessing the cached CTF container and type ID for the common * types "int", "string", and , which we need to use frequently in the D * compiler. The DT_INT_* macro relies upon "int" being at index 0 in the * _dtrace_ints_* tables in dt_open.c; the others are also set up there. */ #define DT_INT_CTFP(dtp) ((dtp)->dt_ints[0].did_ctfp) #define DT_INT_TYPE(dtp) ((dtp)->dt_ints[0].did_type) #define DT_FUNC_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp) #define DT_FUNC_TYPE(dtp) ((dtp)->dt_type_func) #define DT_FPTR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp) #define DT_FPTR_TYPE(dtp) ((dtp)->dt_type_fptr) #define DT_STR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp) #define DT_STR_TYPE(dtp) ((dtp)->dt_type_str) #define DT_DYN_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp) #define DT_DYN_TYPE(dtp) ((dtp)->dt_type_dyn) #define DT_STACK_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp) #define DT_STACK_TYPE(dtp) ((dtp)->dt_type_stack) #define DT_SYMADDR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp) #define DT_SYMADDR_TYPE(dtp) ((dtp)->dt_type_symaddr) #define DT_USYMADDR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp) #define DT_USYMADDR_TYPE(dtp) ((dtp)->dt_type_usymaddr) /* * Actions and subroutines are both DT_NODE_FUNC nodes; to avoid confusing * an action for a subroutine (or vice versa), we assure that the DT_ACT_* * constants and the DIF_SUBR_* constants occupy non-overlapping ranges by * starting the DT_ACT_* constants at DIF_SUBR_MAX + 1. */ #define DT_ACT_BASE DIF_SUBR_MAX + 1 #define DT_ACT(n) (DT_ACT_BASE + (n)) #define DT_ACT_PRINTF DT_ACT(0) /* printf() action */ #define DT_ACT_TRACE DT_ACT(1) /* trace() action */ #define DT_ACT_TRACEMEM DT_ACT(2) /* tracemem() action */ #define DT_ACT_STACK DT_ACT(3) /* stack() action */ #define DT_ACT_STOP DT_ACT(4) /* stop() action */ #define DT_ACT_BREAKPOINT DT_ACT(5) /* breakpoint() action */ #define DT_ACT_PANIC DT_ACT(6) /* panic() action */ #define DT_ACT_SPECULATE DT_ACT(7) /* speculate() action */ #define DT_ACT_COMMIT DT_ACT(8) /* commit() action */ #define DT_ACT_DISCARD DT_ACT(9) /* discard() action */ #define DT_ACT_CHILL DT_ACT(10) /* chill() action */ #define DT_ACT_EXIT DT_ACT(11) /* exit() action */ #define DT_ACT_USTACK DT_ACT(12) /* ustack() action */ #define DT_ACT_PRINTA DT_ACT(13) /* printa() action */ #define DT_ACT_RAISE DT_ACT(14) /* raise() action */ #define DT_ACT_CLEAR DT_ACT(15) /* clear() action */ #define DT_ACT_NORMALIZE DT_ACT(16) /* normalize() action */ #define DT_ACT_DENORMALIZE DT_ACT(17) /* denormalize() action */ #define DT_ACT_TRUNC DT_ACT(18) /* trunc() action */ #define DT_ACT_SYSTEM DT_ACT(19) /* system() action */ #define DT_ACT_JSTACK DT_ACT(20) /* jstack() action */ #define DT_ACT_FTRUNCATE DT_ACT(21) /* ftruncate() action */ #define DT_ACT_FREOPEN DT_ACT(22) /* freopen() action */ #define DT_ACT_SYM DT_ACT(23) /* sym()/func() actions */ #define DT_ACT_MOD DT_ACT(24) /* mod() action */ #define DT_ACT_USYM DT_ACT(25) /* usym()/ufunc() actions */ #define DT_ACT_UMOD DT_ACT(26) /* umod() action */ #define DT_ACT_UADDR DT_ACT(27) /* uaddr() action */ #define DT_ACT_SETOPT DT_ACT(28) /* setopt() action */ #define DT_ACT_PRINT DT_ACT(29) /* print() action */ #define DT_ACT_PRINTM DT_ACT(30) /* printm() action */ /* * Sentinel to tell freopen() to restore the saved stdout. This must not * be ever valid for opening for write access via freopen(3C), which of * course, "." never is. */ #define DT_FREOPEN_RESTORE "." #define EDT_BASE 1000 /* base value for libdtrace errnos */ enum { EDT_VERSION = EDT_BASE, /* client is requesting unsupported version */ EDT_VERSINVAL, /* version string is invalid or overflows */ EDT_VERSUNDEF, /* requested API version is not defined */ EDT_VERSREDUCED, /* requested API version has been reduced */ EDT_CTF, /* libctf called failed (dt_ctferr has more) */ EDT_COMPILER, /* error in D program compilation */ EDT_NOTUPREG, /* tuple register allocation failure */ EDT_NOMEM, /* memory allocation failure */ EDT_INT2BIG, /* integer limit exceeded */ EDT_STR2BIG, /* string limit exceeded */ EDT_NOMOD, /* unknown module name */ EDT_NOPROV, /* unknown provider name */ EDT_NOPROBE, /* unknown probe name */ EDT_NOSYM, /* unknown symbol name */ EDT_NOSYMADDR, /* no symbol corresponds to address */ EDT_NOTYPE, /* unknown type name */ EDT_NOVAR, /* unknown variable name */ EDT_NOAGG, /* unknown aggregation name */ EDT_BADSCOPE, /* improper use of type name scoping operator */ EDT_BADSPEC, /* overspecified probe description */ EDT_BADSPCV, /* bad macro variable in probe description */ EDT_BADID, /* invalid probe identifier */ EDT_NOTLOADED, /* module is not currently loaded */ EDT_NOCTF, /* module does not contain any CTF data */ EDT_DATAMODEL, /* module and program data models don't match */ EDT_DIFVERS, /* library has newer DIF version than driver */ EDT_BADAGG, /* unrecognized aggregating action */ EDT_FIO, /* file i/o error */ EDT_DIFINVAL, /* invalid DIF program */ EDT_DIFSIZE, /* invalid DIF size */ EDT_DIFFAULT, /* failed to copyin DIF program */ EDT_BADPROBE, /* bad probe description */ EDT_BADPGLOB, /* bad probe description globbing pattern */ EDT_NOSCOPE, /* declaration scope stack underflow */ EDT_NODECL, /* declaration stack underflow */ EDT_DMISMATCH, /* record list does not match statement */ EDT_DOFFSET, /* record data offset error */ EDT_DALIGN, /* record data alignment error */ EDT_BADOPTNAME, /* invalid dtrace_setopt option name */ EDT_BADOPTVAL, /* invalid dtrace_setopt option value */ EDT_BADOPTCTX, /* invalid dtrace_setopt option context */ EDT_CPPFORK, /* failed to fork preprocessor */ EDT_CPPEXEC, /* failed to exec preprocessor */ EDT_CPPENT, /* preprocessor not found */ EDT_CPPERR, /* unknown preprocessor error */ EDT_SYMOFLOW, /* external symbol table overflow */ EDT_ACTIVE, /* operation illegal when tracing is active */ EDT_DESTRUCTIVE, /* destructive actions not allowed */ EDT_NOANON, /* no anonymous tracing state */ EDT_ISANON, /* can't claim anon state and enable probes */ EDT_ENDTOOBIG, /* END enablings exceed size of prncpl buffer */ EDT_NOCONV, /* failed to load type for printf conversion */ EDT_BADCONV, /* incomplete printf conversion */ EDT_BADERROR, /* invalid library ERROR action */ EDT_ERRABORT, /* abort due to error */ EDT_DROPABORT, /* abort due to drop */ EDT_DIRABORT, /* abort explicitly directed */ EDT_BADRVAL, /* invalid return value from callback */ EDT_BADNORMAL, /* invalid normalization */ EDT_BUFTOOSMALL, /* enabling exceeds size of buffer */ EDT_BADTRUNC, /* invalid truncation */ EDT_BUSY, /* device busy (active kernel debugger) */ EDT_ACCESS, /* insufficient privileges to use DTrace */ EDT_NOENT, /* dtrace device not available */ EDT_BRICKED, /* abort due to systemic unresponsiveness */ EDT_HARDWIRE, /* failed to load hard-wired definitions */ EDT_ELFVERSION, /* libelf is out-of-date w.r.t libdtrace */ EDT_NOBUFFERED, /* attempt to buffer output without handler */ EDT_UNSTABLE, /* description matched unstable set of probes */ EDT_BADSETOPT, /* invalid setopt library action */ EDT_BADSTACKPC, /* invalid stack program counter size */ EDT_BADAGGVAR, /* invalid aggregation variable identifier */ EDT_OVERSION, /* client is requesting deprecated version */ EDT_ENABLING_ERR, /* failed to enable probe */ EDT_NOPROBES, /* no probes sites for declared provider */ EDT_CANTLOAD /* failed to load a module */ }; /* * Interfaces for parsing and comparing DTrace attribute tuples, which describe * stability and architectural binding information. The dtrace_attribute_t * structure and associated constant definitions are found in . */ extern dtrace_attribute_t dt_attr_min(dtrace_attribute_t, dtrace_attribute_t); extern dtrace_attribute_t dt_attr_max(dtrace_attribute_t, dtrace_attribute_t); extern char *dt_attr_str(dtrace_attribute_t, char *, size_t); extern int dt_attr_cmp(dtrace_attribute_t, dtrace_attribute_t); /* * Interfaces for parsing and handling DTrace version strings. Version binding * is a feature of the D compiler that is handled completely independently of * the DTrace kernel infrastructure, so the definitions are here in libdtrace. * Version strings are compiled into an encoded uint32_t which can be compared * using C comparison operators. Version definitions are found in dt_open.c. */ #define DT_VERSION_STRMAX 16 /* enough for "255.4095.4095\0" */ #define DT_VERSION_MAJMAX 0xFF /* maximum major version number */ #define DT_VERSION_MINMAX 0xFFF /* maximum minor version number */ #define DT_VERSION_MICMAX 0xFFF /* maximum micro version number */ #define DT_VERSION_NUMBER(M, m, u) \ ((((M) & 0xFF) << 24) | (((m) & 0xFFF) << 12) | ((u) & 0xFFF)) #define DT_VERSION_MAJOR(v) (((v) & 0xFF000000) >> 24) #define DT_VERSION_MINOR(v) (((v) & 0x00FFF000) >> 12) #define DT_VERSION_MICRO(v) ((v) & 0x00000FFF) extern char *dt_version_num2str(dt_version_t, char *, size_t); extern int dt_version_str2num(const char *, dt_version_t *); extern int dt_version_defined(dt_version_t); /* * Miscellaneous internal libdtrace interfaces. The definitions below are for * libdtrace routines that do not yet merit their own separate header file. */ extern char *dt_cpp_add_arg(dtrace_hdl_t *, const char *); extern char *dt_cpp_pop_arg(dtrace_hdl_t *); #ifdef illumos extern int dt_set_errno(dtrace_hdl_t *, int); #else int _dt_set_errno(dtrace_hdl_t *, int, const char *, int); void dt_get_errloc(dtrace_hdl_t *, const char **, int *); #define dt_set_errno(_a,_b) _dt_set_errno(_a,_b,__FILE__,__LINE__) #endif extern void dt_set_errmsg(dtrace_hdl_t *, const char *, const char *, const char *, int, const char *, va_list); #ifdef illumos extern int dt_ioctl(dtrace_hdl_t *, int, void *); #else extern int dt_ioctl(dtrace_hdl_t *, u_long, void *); #endif extern int dt_status(dtrace_hdl_t *, processorid_t); extern long dt_sysconf(dtrace_hdl_t *, int); extern ssize_t dt_write(dtrace_hdl_t *, int, const void *, size_t); extern int dt_printf(dtrace_hdl_t *, FILE *, const char *, ...); extern void *dt_zalloc(dtrace_hdl_t *, size_t); extern void *dt_alloc(dtrace_hdl_t *, size_t); extern void dt_free(dtrace_hdl_t *, void *); extern void dt_difo_free(dtrace_hdl_t *, dtrace_difo_t *); extern int dt_gmatch(const char *, const char *); extern char *dt_basename(char *); extern ulong_t dt_popc(ulong_t); extern ulong_t dt_popcb(const ulong_t *, ulong_t); extern int dt_buffered_enable(dtrace_hdl_t *); extern int dt_buffered_flush(dtrace_hdl_t *, dtrace_probedata_t *, const dtrace_recdesc_t *, const dtrace_aggdata_t *, uint32_t flags); extern void dt_buffered_disable(dtrace_hdl_t *); extern void dt_buffered_destroy(dtrace_hdl_t *); extern uint64_t dt_stddev(uint64_t *, uint64_t); extern int dt_rw_read_held(pthread_rwlock_t *); extern int dt_rw_write_held(pthread_rwlock_t *); extern int dt_mutex_held(pthread_mutex_t *); extern int dt_options_load(dtrace_hdl_t *); #define DT_RW_READ_HELD(x) dt_rw_read_held(x) #define DT_RW_WRITE_HELD(x) dt_rw_write_held(x) #define DT_RW_LOCK_HELD(x) (DT_RW_READ_HELD(x) || DT_RW_WRITE_HELD(x)) #define DT_MUTEX_HELD(x) dt_mutex_held(x) extern void dt_dprintf(const char *, ...); extern void dt_setcontext(dtrace_hdl_t *, dtrace_probedesc_t *); extern void dt_endcontext(dtrace_hdl_t *); extern void dt_pragma(dt_node_t *); extern int dt_reduce(dtrace_hdl_t *, dt_version_t); extern void dt_cg(dt_pcb_t *, dt_node_t *); extern dtrace_difo_t *dt_as(dt_pcb_t *); extern void dt_dis(const dtrace_difo_t *, FILE *); extern int dt_aggregate_go(dtrace_hdl_t *); extern int dt_aggregate_init(dtrace_hdl_t *); extern void dt_aggregate_destroy(dtrace_hdl_t *); extern int dt_epid_lookup(dtrace_hdl_t *, dtrace_epid_t, dtrace_eprobedesc_t **, dtrace_probedesc_t **); extern void dt_epid_destroy(dtrace_hdl_t *); extern int dt_aggid_lookup(dtrace_hdl_t *, dtrace_aggid_t, dtrace_aggdesc_t **); extern void dt_aggid_destroy(dtrace_hdl_t *); extern void *dt_format_lookup(dtrace_hdl_t *, int); extern void dt_format_destroy(dtrace_hdl_t *); extern const char *dt_strdata_lookup(dtrace_hdl_t *, int); extern void dt_strdata_destroy(dtrace_hdl_t *); extern int dt_print_quantize(dtrace_hdl_t *, FILE *, const void *, size_t, uint64_t); extern int dt_print_lquantize(dtrace_hdl_t *, FILE *, const void *, size_t, uint64_t); extern int dt_print_llquantize(dtrace_hdl_t *, FILE *, const void *, size_t, uint64_t); extern int dt_print_agg(const dtrace_aggdata_t *, void *); extern int dt_handle(dtrace_hdl_t *, dtrace_probedata_t *); extern int dt_handle_liberr(dtrace_hdl_t *, const dtrace_probedata_t *, const char *); extern int dt_handle_cpudrop(dtrace_hdl_t *, processorid_t, dtrace_dropkind_t, uint64_t); extern int dt_handle_status(dtrace_hdl_t *, dtrace_status_t *, dtrace_status_t *); extern int dt_handle_setopt(dtrace_hdl_t *, dtrace_setoptdata_t *); extern int dt_lib_depend_add(dtrace_hdl_t *, dt_list_t *, const char *); extern dt_lib_depend_t *dt_lib_depend_lookup(dt_list_t *, const char *); extern dt_pcb_t *yypcb; /* pointer to current parser control block */ extern char yyintprefix; /* int token prefix for macros (+/-) */ extern char yyintsuffix[4]; /* int token suffix ([uUlL]*) */ extern int yyintdecimal; /* int token is decimal (1) or octal/hex (0) */ extern char *yytext; /* lex input buffer */ extern int yylineno; /* lex line number */ extern int yydebug; /* lex debugging */ extern dt_node_t *yypragma; /* lex token list for control lines */ extern const dtrace_attribute_t _dtrace_maxattr; /* maximum attributes */ extern const dtrace_attribute_t _dtrace_defattr; /* default attributes */ extern const dtrace_attribute_t _dtrace_symattr; /* symbol ref attributes */ extern const dtrace_attribute_t _dtrace_typattr; /* type ref attributes */ extern const dtrace_attribute_t _dtrace_prvattr; /* provider attributes */ extern const dtrace_pattr_t _dtrace_prvdesc; /* provider attribute bundle */ extern const dt_version_t _dtrace_versions[]; /* array of valid versions */ extern const char *const _dtrace_version; /* current version string */ extern int _dtrace_strbuckets; /* number of hash buckets for strings */ extern int _dtrace_intbuckets; /* number of hash buckets for ints */ extern uint_t _dtrace_stkindent; /* default indent for stack/ustack */ extern uint_t _dtrace_pidbuckets; /* number of hash buckets for pids */ extern uint_t _dtrace_pidlrulim; /* number of proc handles to cache */ extern int _dtrace_debug; /* debugging messages enabled */ extern size_t _dtrace_bufsize; /* default dt_buf_create() size */ extern int _dtrace_argmax; /* default maximum probe arguments */ extern const char *_dtrace_libdir; /* default library directory */ extern const char *_dtrace_moddir; /* default kernel module directory */ #ifdef __FreeBSD__ extern int gmatch(const char *, const char *); extern int yylex(void); #endif #ifdef __cplusplus } #endif #endif /* _DT_IMPL_H */ diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c index 9621a0fcb391..867259b5d77c 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c @@ -1,1748 +1,1751 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. * Copyright (c) 2012, 2016 by Delphix. All rights reserved. */ #include #ifdef illumos #include #include #else #include #include #include #endif #include #include #include #ifdef illumos #include #endif #include #include #include #include #include #include #include #define _POSIX_PTHREAD_SEMANTICS #include #undef _POSIX_PTHREAD_SEMANTICS #include #include #include #include #include #include #ifndef illumos #include #include #endif #if defined(__i386__) #include #endif /* * Stability and versioning definitions. These #defines are used in the tables * of identifiers below to fill in the attribute and version fields associated * with each identifier. The DT_ATTR_* macros are a convenience to permit more * concise declarations of common attributes such as Stable/Stable/Common. The * DT_VERS_* macros declare the encoded integer values of all versions used so * far. DT_VERS_LATEST must correspond to the latest version value among all * versions exported by the D compiler. DT_VERS_STRING must be an ASCII string * that contains DT_VERS_LATEST within it along with any suffixes (e.g. Beta). * You must update DT_VERS_LATEST and DT_VERS_STRING when adding a new version, * and then add the new version to the _dtrace_versions[] array declared below. * Refer to the Solaris Dynamic Tracing Guide Stability and Versioning chapters * respectively for an explanation of these DTrace features and their values. * * NOTE: Although the DTrace versioning scheme supports the labeling and * introduction of incompatible changes (e.g. dropping an interface in a * major release), the libdtrace code does not currently support this. * All versions are assumed to strictly inherit from one another. If * we ever need to provide divergent interfaces, this will need work. */ #define DT_ATTR_STABCMN { DTRACE_STABILITY_STABLE, \ DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON } #define DT_ATTR_EVOLCMN { DTRACE_STABILITY_EVOLVING, \ DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON \ } /* * The version number should be increased for every customer visible release * of DTrace. The major number should be incremented when a fundamental * change has been made that would affect all consumers, and would reflect * sweeping changes to DTrace or the D language. The minor number should be * incremented when a change is introduced that could break scripts that had * previously worked; for example, adding a new built-in variable could break * a script which was already using that identifier. The micro number should * be changed when introducing functionality changes or major bug fixes that * do not affect backward compatibility -- this is merely to make capabilities * easily determined from the version number. Minor bugs do not require any * modification to the version number. */ #define DT_VERS_1_0 DT_VERSION_NUMBER(1, 0, 0) #define DT_VERS_1_1 DT_VERSION_NUMBER(1, 1, 0) #define DT_VERS_1_2 DT_VERSION_NUMBER(1, 2, 0) #define DT_VERS_1_2_1 DT_VERSION_NUMBER(1, 2, 1) #define DT_VERS_1_2_2 DT_VERSION_NUMBER(1, 2, 2) #define DT_VERS_1_3 DT_VERSION_NUMBER(1, 3, 0) #define DT_VERS_1_4 DT_VERSION_NUMBER(1, 4, 0) #define DT_VERS_1_4_1 DT_VERSION_NUMBER(1, 4, 1) #define DT_VERS_1_5 DT_VERSION_NUMBER(1, 5, 0) #define DT_VERS_1_6 DT_VERSION_NUMBER(1, 6, 0) #define DT_VERS_1_6_1 DT_VERSION_NUMBER(1, 6, 1) #define DT_VERS_1_6_2 DT_VERSION_NUMBER(1, 6, 2) #define DT_VERS_1_6_3 DT_VERSION_NUMBER(1, 6, 3) #define DT_VERS_1_7 DT_VERSION_NUMBER(1, 7, 0) #define DT_VERS_1_7_1 DT_VERSION_NUMBER(1, 7, 1) #define DT_VERS_1_8 DT_VERSION_NUMBER(1, 8, 0) #define DT_VERS_1_8_1 DT_VERSION_NUMBER(1, 8, 1) #define DT_VERS_1_9 DT_VERSION_NUMBER(1, 9, 0) #define DT_VERS_1_9_1 DT_VERSION_NUMBER(1, 9, 1) #define DT_VERS_1_10 DT_VERSION_NUMBER(1, 10, 0) #define DT_VERS_1_11 DT_VERSION_NUMBER(1, 11, 0) #define DT_VERS_1_12 DT_VERSION_NUMBER(1, 12, 0) #define DT_VERS_1_12_1 DT_VERSION_NUMBER(1, 12, 1) #define DT_VERS_1_13 DT_VERSION_NUMBER(1, 13, 0) #define DT_VERS_LATEST DT_VERS_1_13 #define DT_VERS_STRING "Sun D 1.13" const dt_version_t _dtrace_versions[] = { DT_VERS_1_0, /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */ DT_VERS_1_1, /* D API 1.1.0 Solaris Express 6/05 */ DT_VERS_1_2, /* D API 1.2.0 Solaris 10 Update 1 */ DT_VERS_1_2_1, /* D API 1.2.1 Solaris Express 4/06 */ DT_VERS_1_2_2, /* D API 1.2.2 Solaris Express 6/06 */ DT_VERS_1_3, /* D API 1.3 Solaris Express 10/06 */ DT_VERS_1_4, /* D API 1.4 Solaris Express 2/07 */ DT_VERS_1_4_1, /* D API 1.4.1 Solaris Express 4/07 */ DT_VERS_1_5, /* D API 1.5 Solaris Express 7/07 */ DT_VERS_1_6, /* D API 1.6 */ DT_VERS_1_6_1, /* D API 1.6.1 */ DT_VERS_1_6_2, /* D API 1.6.2 */ DT_VERS_1_6_3, /* D API 1.6.3 */ DT_VERS_1_7, /* D API 1.7 */ DT_VERS_1_7_1, /* D API 1.7.1 */ DT_VERS_1_8, /* D API 1.8 */ DT_VERS_1_8_1, /* D API 1.8.1 */ DT_VERS_1_9, /* D API 1.9 */ DT_VERS_1_9_1, /* D API 1.9.1 */ DT_VERS_1_10, /* D API 1.10 */ DT_VERS_1_11, /* D API 1.11 */ DT_VERS_1_12, /* D API 1.12 */ DT_VERS_1_12_1, /* D API 1.12.1 */ DT_VERS_1_13, /* D API 1.13 */ 0 }; /* * Global variables that are formatted on FreeBSD based on the kernel file name. */ #ifndef illumos static char curthread_str[MAXPATHLEN]; static char intmtx_str[MAXPATHLEN]; static char threadmtx_str[MAXPATHLEN]; static char rwlock_str[MAXPATHLEN]; static char sxlock_str[MAXPATHLEN]; #endif /* * Table of global identifiers. This is used to populate the global identifier * hash when a new dtrace client open occurs. For more info see dt_ident.h. * The global identifiers that represent functions use the dt_idops_func ops * and specify the private data pointer as a prototype string which is parsed * when the identifier is first encountered. These prototypes look like ANSI * C function prototypes except that the special symbol "@" can be used as a * wildcard to represent a single parameter of any type (i.e. any dt_node_t). * The standard "..." notation can also be used to represent varargs. An empty * parameter list is taken to mean void (that is, no arguments are permitted). * A parameter enclosed in square brackets (e.g. "[int]") denotes an optional * argument. */ static const dt_ident_t _dtrace_globals[] = { { "alloca", DT_IDENT_FUNC, 0, DIF_SUBR_ALLOCA, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void *(size_t)" }, { "arg0", DT_IDENT_SCALAR, 0, DIF_VAR_ARG0, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg1", DT_IDENT_SCALAR, 0, DIF_VAR_ARG1, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg2", DT_IDENT_SCALAR, 0, DIF_VAR_ARG2, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg3", DT_IDENT_SCALAR, 0, DIF_VAR_ARG3, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg4", DT_IDENT_SCALAR, 0, DIF_VAR_ARG4, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg5", DT_IDENT_SCALAR, 0, DIF_VAR_ARG5, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg6", DT_IDENT_SCALAR, 0, DIF_VAR_ARG6, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg7", DT_IDENT_SCALAR, 0, DIF_VAR_ARG7, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg8", DT_IDENT_SCALAR, 0, DIF_VAR_ARG8, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg9", DT_IDENT_SCALAR, 0, DIF_VAR_ARG9, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "args", DT_IDENT_ARRAY, 0, DIF_VAR_ARGS, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_args, NULL }, { "avg", DT_IDENT_AGGFUNC, 0, DTRACEAGG_AVG, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, { "basename", DT_IDENT_FUNC, 0, DIF_SUBR_BASENAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(const char *)" }, { "bcopy", DT_IDENT_FUNC, 0, DIF_SUBR_BCOPY, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(void *, void *, size_t)" }, { "breakpoint", DT_IDENT_ACTFUNC, 0, DT_ACT_BREAKPOINT, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void()" }, { "caller", DT_IDENT_SCALAR, 0, DIF_VAR_CALLER, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uintptr_t" }, { "chill", DT_IDENT_ACTFUNC, 0, DT_ACT_CHILL, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "cleanpath", DT_IDENT_FUNC, 0, DIF_SUBR_CLEANPATH, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(const char *)" }, { "clear", DT_IDENT_ACTFUNC, 0, DT_ACT_CLEAR, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(...)" }, { "commit", DT_IDENT_ACTFUNC, 0, DT_ACT_COMMIT, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "copyin", DT_IDENT_FUNC, 0, DIF_SUBR_COPYIN, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void *(uintptr_t, size_t)" }, { "copyinstr", DT_IDENT_FUNC, 0, DIF_SUBR_COPYINSTR, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(uintptr_t, [size_t])" }, { "copyinto", DT_IDENT_FUNC, 0, DIF_SUBR_COPYINTO, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(uintptr_t, size_t, void *)" }, { "copyout", DT_IDENT_FUNC, 0, DIF_SUBR_COPYOUT, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(void *, uintptr_t, size_t)" }, { "copyoutstr", DT_IDENT_FUNC, 0, DIF_SUBR_COPYOUTSTR, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(char *, uintptr_t, size_t)" }, { "count", DT_IDENT_AGGFUNC, 0, DTRACEAGG_COUNT, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void()" }, { "curthread", DT_IDENT_SCALAR, 0, DIF_VAR_CURTHREAD, { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_COMMON }, DT_VERS_1_0, #ifdef illumos &dt_idops_type, "genunix`kthread_t *" }, #else &dt_idops_type, curthread_str }, #endif { "ddi_pathname", DT_IDENT_FUNC, 0, DIF_SUBR_DDI_PATHNAME, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "string(void *, int64_t)" }, { "denormalize", DT_IDENT_ACTFUNC, 0, DT_ACT_DENORMALIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(...)" }, { "dirname", DT_IDENT_FUNC, 0, DIF_SUBR_DIRNAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(const char *)" }, { "discard", DT_IDENT_ACTFUNC, 0, DT_ACT_DISCARD, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "epid", DT_IDENT_SCALAR, 0, DIF_VAR_EPID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint_t" }, { "errno", DT_IDENT_SCALAR, 0, DIF_VAR_ERRNO, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int" }, { "execargs", DT_IDENT_SCALAR, 0, DIF_VAR_EXECARGS, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "exit", DT_IDENT_ACTFUNC, 0, DT_ACT_EXIT, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "freopen", DT_IDENT_ACTFUNC, 0, DT_ACT_FREOPEN, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "void(@, ...)" }, { "ftruncate", DT_IDENT_ACTFUNC, 0, DT_ACT_FTRUNCATE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void()" }, { "func", DT_IDENT_ACTFUNC, 0, DT_ACT_SYM, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" }, { "getmajor", DT_IDENT_FUNC, 0, DIF_SUBR_GETMAJOR, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "genunix`major_t(genunix`dev_t)" }, { "getminor", DT_IDENT_FUNC, 0, DIF_SUBR_GETMINOR, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "genunix`minor_t(genunix`dev_t)" }, { "htonl", DT_IDENT_FUNC, 0, DIF_SUBR_HTONL, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint32_t(uint32_t)" }, { "htonll", DT_IDENT_FUNC, 0, DIF_SUBR_HTONLL, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint64_t(uint64_t)" }, { "htons", DT_IDENT_FUNC, 0, DIF_SUBR_HTONS, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint16_t(uint16_t)" }, { "getf", DT_IDENT_FUNC, 0, DIF_SUBR_GETF, DT_ATTR_STABCMN, DT_VERS_1_10, &dt_idops_func, "file_t *(int)" }, { "gid", DT_IDENT_SCALAR, 0, DIF_VAR_GID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "gid_t" }, { "id", DT_IDENT_SCALAR, 0, DIF_VAR_ID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint_t" }, { "index", DT_IDENT_FUNC, 0, DIF_SUBR_INDEX, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "int(const char *, const char *, [int])" }, { "inet_ntoa", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA, DT_ATTR_STABCMN, #ifdef illumos DT_VERS_1_5, &dt_idops_func, "string(ipaddr_t *)" }, #else DT_VERS_1_5, &dt_idops_func, "string(in_addr_t *)" }, #endif { "inet_ntoa6", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOA6, DT_ATTR_STABCMN, #ifdef illumos DT_VERS_1_5, &dt_idops_func, "string(in6_addr_t *)" }, #else DT_VERS_1_5, &dt_idops_func, "string(struct in6_addr *)" }, #endif { "inet_ntop", DT_IDENT_FUNC, 0, DIF_SUBR_INET_NTOP, DT_ATTR_STABCMN, DT_VERS_1_5, &dt_idops_func, "string(int, void *)" }, { "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint_t" }, #ifdef __FreeBSD__ { "jailname", DT_IDENT_SCALAR, 0, DIF_VAR_JAILNAME, DT_ATTR_STABCMN, DT_VERS_1_13, &dt_idops_type, "string" }, { "jid", DT_IDENT_SCALAR, 0, DIF_VAR_JID, DT_ATTR_STABCMN, DT_VERS_1_13, &dt_idops_type, "int" }, #endif { "json", DT_IDENT_FUNC, 0, DIF_SUBR_JSON, DT_ATTR_STABCMN, DT_VERS_1_11, &dt_idops_func, "string(const char *, const char *)" }, { "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "stack(...)" }, { "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(int64_t, [int])" }, { "llquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LLQUANTIZE, DT_ATTR_STABCMN, DT_VERS_1_7, &dt_idops_func, "void(@, int32_t, int32_t, int32_t, int32_t, ...)" }, { "lquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LQUANTIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, int32_t, int32_t, ...)" }, { "max", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MAX, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, { "memref", DT_IDENT_FUNC, 0, DIF_SUBR_MEMREF, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "uintptr_t *(void *, size_t)" }, #ifndef illumos { "memstr", DT_IDENT_FUNC, 0, DIF_SUBR_MEMSTR, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(void *, char, size_t)" }, #endif { "min", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MIN, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, { "mod", DT_IDENT_ACTFUNC, 0, DT_ACT_MOD, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" }, #ifdef illumos { "msgdsize", DT_IDENT_FUNC, 0, DIF_SUBR_MSGDSIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "size_t(mblk_t *)" }, { "msgsize", DT_IDENT_FUNC, 0, DIF_SUBR_MSGSIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "size_t(mblk_t *)" }, { "mutex_owned", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNED, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`kmutex_t *)" }, { "mutex_owner", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNER, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "genunix`kthread_t *(genunix`kmutex_t *)" }, { "mutex_type_adaptive", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_ADAPTIVE, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`kmutex_t *)" }, { "mutex_type_spin", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_SPIN, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`kmutex_t *)" }, #else { "mutex_owned", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNED, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, intmtx_str }, { "mutex_owner", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_OWNER, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, threadmtx_str }, { "mutex_type_adaptive", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_ADAPTIVE, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, intmtx_str }, { "mutex_type_spin", DT_IDENT_FUNC, 0, DIF_SUBR_MUTEX_TYPE_SPIN, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, intmtx_str }, #endif { "ntohl", DT_IDENT_FUNC, 0, DIF_SUBR_NTOHL, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint32_t(uint32_t)" }, { "ntohll", DT_IDENT_FUNC, 0, DIF_SUBR_NTOHLL, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint64_t(uint64_t)" }, { "ntohs", DT_IDENT_FUNC, 0, DIF_SUBR_NTOHS, DT_ATTR_EVOLCMN, DT_VERS_1_3, &dt_idops_func, "uint16_t(uint16_t)" }, { "normalize", DT_IDENT_ACTFUNC, 0, DT_ACT_NORMALIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(...)" }, { "panic", DT_IDENT_ACTFUNC, 0, DT_ACT_PANIC, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void()" }, { "pid", DT_IDENT_SCALAR, 0, DIF_VAR_PID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "pid_t" }, { "ppid", DT_IDENT_SCALAR, 0, DIF_VAR_PPID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "pid_t" }, { "print", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINT, DT_ATTR_STABCMN, DT_VERS_1_9, &dt_idops_func, "void(@)" }, { "printa", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTA, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, ...)" }, { "printf", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTF, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, ...)" }, { "printm", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTM, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(size_t, uintptr_t *)" }, { "probefunc", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEFUNC, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "probemod", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEMOD, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "probename", DT_IDENT_SCALAR, 0, DIF_VAR_PROBENAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "probeprov", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEPROV, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, { "progenyof", DT_IDENT_FUNC, 0, DIF_SUBR_PROGENYOF, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "int(pid_t)" }, { "quantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_QUANTIZE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, ...)" }, { "raise", DT_IDENT_ACTFUNC, 0, DT_ACT_RAISE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "rand", DT_IDENT_FUNC, 0, DIF_SUBR_RAND, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "int()" }, { "regs", DT_IDENT_ARRAY, 0, DIF_VAR_REGS, DT_ATTR_STABCMN, DT_VERS_1_13, &dt_idops_regs, NULL }, { "rindex", DT_IDENT_FUNC, 0, DIF_SUBR_RINDEX, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "int(const char *, const char *, [int])" }, #ifdef illumos { "rw_iswriter", DT_IDENT_FUNC, 0, DIF_SUBR_RW_ISWRITER, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`krwlock_t *)" }, { "rw_read_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_READ_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`krwlock_t *)" }, { "rw_write_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_WRITE_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, "int(genunix`krwlock_t *)" }, #else { "rw_iswriter", DT_IDENT_FUNC, 0, DIF_SUBR_RW_ISWRITER, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, rwlock_str }, { "rw_read_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_READ_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, rwlock_str }, { "rw_write_held", DT_IDENT_FUNC, 0, DIF_SUBR_RW_WRITE_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, rwlock_str }, #endif { "self", DT_IDENT_PTR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "void" }, { "setopt", DT_IDENT_ACTFUNC, 0, DT_ACT_SETOPT, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "void(const char *, [const char *])" }, { "speculate", DT_IDENT_ACTFUNC, 0, DT_ACT_SPECULATE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(int)" }, { "speculation", DT_IDENT_FUNC, 0, DIF_SUBR_SPECULATION, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "int()" }, { "stack", DT_IDENT_ACTFUNC, 0, DT_ACT_STACK, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "stack(...)" }, { "stackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_STACKDEPTH, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint32_t" }, { "stddev", DT_IDENT_AGGFUNC, 0, DTRACEAGG_STDDEV, DT_ATTR_STABCMN, DT_VERS_1_6, &dt_idops_func, "void(@)" }, { "stop", DT_IDENT_ACTFUNC, 0, DT_ACT_STOP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void()" }, { "strchr", DT_IDENT_FUNC, 0, DIF_SUBR_STRCHR, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, char)" }, { "strlen", DT_IDENT_FUNC, 0, DIF_SUBR_STRLEN, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "size_t(const char *)" }, { "strjoin", DT_IDENT_FUNC, 0, DIF_SUBR_STRJOIN, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "string(const char *, const char *)" }, { "strrchr", DT_IDENT_FUNC, 0, DIF_SUBR_STRRCHR, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, char)" }, { "strstr", DT_IDENT_FUNC, 0, DIF_SUBR_STRSTR, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, const char *)" }, { "strtok", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOK, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, const char *)" }, { "strtoll", DT_IDENT_FUNC, 0, DIF_SUBR_STRTOLL, DT_ATTR_STABCMN, DT_VERS_1_11, &dt_idops_func, "int64_t(const char *, [int])" }, { "substr", DT_IDENT_FUNC, 0, DIF_SUBR_SUBSTR, DT_ATTR_STABCMN, DT_VERS_1_1, &dt_idops_func, "string(const char *, int, [int])" }, { "sum", DT_IDENT_AGGFUNC, 0, DTRACEAGG_SUM, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, #ifndef illumos { "sx_isexclusive", DT_IDENT_FUNC, 0, DIF_SUBR_SX_ISEXCLUSIVE, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, sxlock_str }, { "sx_shared_held", DT_IDENT_FUNC, 0, DIF_SUBR_SX_SHARED_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, sxlock_str }, { "sx_exclusive_held", DT_IDENT_FUNC, 0, DIF_SUBR_SX_EXCLUSIVE_HELD, DT_ATTR_EVOLCMN, DT_VERS_1_0, &dt_idops_func, sxlock_str }, #endif { "sym", DT_IDENT_ACTFUNC, 0, DT_ACT_SYM, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_symaddr(uintptr_t)" }, { "system", DT_IDENT_ACTFUNC, 0, DT_ACT_SYSTEM, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, ...)" }, { "this", DT_IDENT_PTR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "void" }, { "tid", DT_IDENT_SCALAR, 0, DIF_VAR_TID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "id_t" }, { "timestamp", DT_IDENT_SCALAR, 0, DIF_VAR_TIMESTAMP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint64_t" }, { "tolower", DT_IDENT_FUNC, 0, DIF_SUBR_TOLOWER, DT_ATTR_STABCMN, DT_VERS_1_8, &dt_idops_func, "string(const char *)" }, { "toupper", DT_IDENT_FUNC, 0, DIF_SUBR_TOUPPER, DT_ATTR_STABCMN, DT_VERS_1_8, &dt_idops_func, "string(const char *)" }, { "trace", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACE, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@)" }, { "tracemem", DT_IDENT_ACTFUNC, 0, DT_ACT_TRACEMEM, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(@, size_t, ...)" }, { "trunc", DT_IDENT_ACTFUNC, 0, DT_ACT_TRUNC, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void(...)" }, { "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, { "ucaller", DT_IDENT_SCALAR, 0, DIF_VAR_UCALLER, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_type, "uint64_t" }, { "ufunc", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, { "uid", DT_IDENT_SCALAR, 0, DIF_VAR_UID, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uid_t" }, { "umod", DT_IDENT_ACTFUNC, 0, DT_ACT_UMOD, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, { "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_regs, NULL }, { "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "stack(...)" }, { "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_type, "uint32_t" }, { "usym", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN, DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" }, { "vtimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_VTIMESTAMP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint64_t" }, { "walltimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_WALLTIMESTAMP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "zonename", DT_IDENT_SCALAR, 0, DIF_VAR_ZONENAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, #ifndef illumos { "cpu", DT_IDENT_SCALAR, 0, DIF_VAR_CPU, DT_ATTR_STABCMN, DT_VERS_1_6_3, &dt_idops_type, "int" }, #endif { NULL, 0, 0, 0, { 0, 0, 0 }, 0, NULL, NULL } }; /* * Tables of ILP32 intrinsic integer and floating-point type templates to use * to populate the dynamic "C" CTF type container. */ static const dt_intrinsic_t _dtrace_intrinsics_32[] = { { "void", { CTF_INT_SIGNED, 0, 0 }, CTF_K_INTEGER }, { "signed", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "unsigned", { 0, 0, 32 }, CTF_K_INTEGER }, { "char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER }, { "int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "long", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "signed char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "signed short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER }, { "signed int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "signed long", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "signed long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "unsigned char", { CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "unsigned short", { 0, 0, 16 }, CTF_K_INTEGER }, { "unsigned int", { 0, 0, 32 }, CTF_K_INTEGER }, { "unsigned long", { 0, 0, 32 }, CTF_K_INTEGER }, { "unsigned long long", { 0, 0, 64 }, CTF_K_INTEGER }, { "_Bool", { CTF_INT_BOOL, 0, 8 }, CTF_K_INTEGER }, { "float", { CTF_FP_SINGLE, 0, 32 }, CTF_K_FLOAT }, { "double", { CTF_FP_DOUBLE, 0, 64 }, CTF_K_FLOAT }, { "long double", { CTF_FP_LDOUBLE, 0, 128 }, CTF_K_FLOAT }, { "float imaginary", { CTF_FP_IMAGRY, 0, 32 }, CTF_K_FLOAT }, { "double imaginary", { CTF_FP_DIMAGRY, 0, 64 }, CTF_K_FLOAT }, { "long double imaginary", { CTF_FP_LDIMAGRY, 0, 128 }, CTF_K_FLOAT }, { "float complex", { CTF_FP_CPLX, 0, 64 }, CTF_K_FLOAT }, { "double complex", { CTF_FP_DCPLX, 0, 128 }, CTF_K_FLOAT }, { "long double complex", { CTF_FP_LDCPLX, 0, 256 }, CTF_K_FLOAT }, { NULL, { 0, 0, 0 }, 0 } }; /* * Tables of LP64 intrinsic integer and floating-point type templates to use * to populate the dynamic "C" CTF type container. */ static const dt_intrinsic_t _dtrace_intrinsics_64[] = { { "void", { CTF_INT_SIGNED, 0, 0 }, CTF_K_INTEGER }, { "signed", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "unsigned", { 0, 0, 32 }, CTF_K_INTEGER }, { "char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER }, { "int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "signed char", { CTF_INT_SIGNED | CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "signed short", { CTF_INT_SIGNED, 0, 16 }, CTF_K_INTEGER }, { "signed int", { CTF_INT_SIGNED, 0, 32 }, CTF_K_INTEGER }, { "signed long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "signed long long", { CTF_INT_SIGNED, 0, 64 }, CTF_K_INTEGER }, { "unsigned char", { CTF_INT_CHAR, 0, 8 }, CTF_K_INTEGER }, { "unsigned short", { 0, 0, 16 }, CTF_K_INTEGER }, { "unsigned int", { 0, 0, 32 }, CTF_K_INTEGER }, { "unsigned long", { 0, 0, 64 }, CTF_K_INTEGER }, { "unsigned long long", { 0, 0, 64 }, CTF_K_INTEGER }, { "_Bool", { CTF_INT_BOOL, 0, 8 }, CTF_K_INTEGER }, { "float", { CTF_FP_SINGLE, 0, 32 }, CTF_K_FLOAT }, { "double", { CTF_FP_DOUBLE, 0, 64 }, CTF_K_FLOAT }, { "long double", { CTF_FP_LDOUBLE, 0, 128 }, CTF_K_FLOAT }, { "float imaginary", { CTF_FP_IMAGRY, 0, 32 }, CTF_K_FLOAT }, { "double imaginary", { CTF_FP_DIMAGRY, 0, 64 }, CTF_K_FLOAT }, { "long double imaginary", { CTF_FP_LDIMAGRY, 0, 128 }, CTF_K_FLOAT }, { "float complex", { CTF_FP_CPLX, 0, 64 }, CTF_K_FLOAT }, { "double complex", { CTF_FP_DCPLX, 0, 128 }, CTF_K_FLOAT }, { "long double complex", { CTF_FP_LDCPLX, 0, 256 }, CTF_K_FLOAT }, { NULL, { 0, 0, 0 }, 0 } }; /* * Tables of ILP32 typedefs to use to populate the dynamic "D" CTF container. * These aliases ensure that D definitions can use typical names. */ static const dt_typedef_t _dtrace_typedefs_32[] = { { "char", "int8_t" }, { "short", "int16_t" }, { "int", "int32_t" }, { "long long", "int64_t" }, { "int", "intptr_t" }, { "int", "ssize_t" }, { "unsigned char", "uint8_t" }, { "unsigned short", "uint16_t" }, { "unsigned", "uint32_t" }, { "unsigned long long", "uint64_t" }, { "unsigned char", "uchar_t" }, { "unsigned short", "ushort_t" }, { "unsigned", "uint_t" }, { "unsigned long", "ulong_t" }, { "unsigned long long", "u_longlong_t" }, { "int", "ptrdiff_t" }, { "unsigned", "uintptr_t" }, { "unsigned", "size_t" }, { "long", "id_t" }, { "long", "pid_t" }, { NULL, NULL } }; /* * Tables of LP64 typedefs to use to populate the dynamic "D" CTF container. * These aliases ensure that D definitions can use typical names. */ static const dt_typedef_t _dtrace_typedefs_64[] = { { "char", "int8_t" }, { "short", "int16_t" }, { "int", "int32_t" }, { "long", "int64_t" }, { "long", "intptr_t" }, { "long", "ssize_t" }, { "unsigned char", "uint8_t" }, { "unsigned short", "uint16_t" }, { "unsigned", "uint32_t" }, { "unsigned long", "uint64_t" }, { "unsigned char", "uchar_t" }, { "unsigned short", "ushort_t" }, { "unsigned", "uint_t" }, { "unsigned long", "ulong_t" }, { "unsigned long long", "u_longlong_t" }, { "long", "ptrdiff_t" }, { "unsigned long", "uintptr_t" }, { "unsigned long", "size_t" }, { "int", "id_t" }, { "int", "pid_t" }, { NULL, NULL } }; /* * Tables of ILP32 integer type templates used to populate the dtp->dt_ints[] * cache when a new dtrace client open occurs. Values are set by dtrace_open(). */ static const dt_intdesc_t _dtrace_ints_32[] = { { "int", NULL, CTF_ERR, 0x7fffffffULL }, { "unsigned int", NULL, CTF_ERR, 0xffffffffULL }, { "long", NULL, CTF_ERR, 0x7fffffffULL }, { "unsigned long", NULL, CTF_ERR, 0xffffffffULL }, { "long long", NULL, CTF_ERR, 0x7fffffffffffffffULL }, { "unsigned long long", NULL, CTF_ERR, 0xffffffffffffffffULL } }; /* * Tables of LP64 integer type templates used to populate the dtp->dt_ints[] * cache when a new dtrace client open occurs. Values are set by dtrace_open(). */ static const dt_intdesc_t _dtrace_ints_64[] = { { "int", NULL, CTF_ERR, 0x7fffffffULL }, { "unsigned int", NULL, CTF_ERR, 0xffffffffULL }, { "long", NULL, CTF_ERR, 0x7fffffffffffffffULL }, { "unsigned long", NULL, CTF_ERR, 0xffffffffffffffffULL }, { "long long", NULL, CTF_ERR, 0x7fffffffffffffffULL }, { "unsigned long long", NULL, CTF_ERR, 0xffffffffffffffffULL } }; /* * Table of macro variable templates used to populate the macro identifier hash * when a new dtrace client open occurs. Values are set by dtrace_update(). */ static const dt_ident_t _dtrace_macros[] = { { "egid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "euid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "gid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "pid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "pgid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "ppid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "projid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "sid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "taskid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "target", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { "uid", DT_IDENT_SCALAR, 0, 0, DT_ATTR_STABCMN, DT_VERS_1_0 }, { NULL, 0, 0, 0, { 0, 0, 0 }, 0 } }; /* * Hard-wired definition string to be compiled and cached every time a new * DTrace library handle is initialized. This string should only be used to * contain definitions that should be present regardless of DTRACE_O_NOLIBS. */ static const char _dtrace_hardwire[] = "\ inline long NULL = 0; \n\ #pragma D binding \"1.0\" NULL\n\ "; /* * Default DTrace configuration to use when opening libdtrace DTRACE_O_NODEV. * If DTRACE_O_NODEV is not set, we load the configuration from the kernel. * The use of CTF_MODEL_NATIVE is more subtle than it might appear: we are * relying on the fact that when running dtrace(1M), isaexec will invoke the * binary with the same bitness as the kernel, which is what we want by default * when generating our DIF. The user can override the choice using oflags. */ static const dtrace_conf_t _dtrace_conf = { DIF_VERSION, /* dtc_difversion */ DIF_DIR_NREGS, /* dtc_difintregs */ DIF_DTR_NREGS, /* dtc_diftupregs */ CTF_MODEL_NATIVE /* dtc_ctfmodel */ }; const dtrace_attribute_t _dtrace_maxattr = { DTRACE_STABILITY_MAX, DTRACE_STABILITY_MAX, DTRACE_CLASS_MAX }; const dtrace_attribute_t _dtrace_defattr = { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }; const dtrace_attribute_t _dtrace_symattr = { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }; const dtrace_attribute_t _dtrace_typattr = { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }; const dtrace_attribute_t _dtrace_prvattr = { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }; const dtrace_pattr_t _dtrace_prvdesc = { { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON }, { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON }, { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON }, { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON }, { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_COMMON }, }; #ifdef illumos const char *_dtrace_defcpp = "/usr/ccs/lib/cpp"; /* default cpp(1) to invoke */ const char *_dtrace_defld = "/usr/ccs/bin/ld"; /* default ld(1) to invoke */ #else const char *_dtrace_defcpp = "cpp"; /* default cpp(1) to invoke */ const char *_dtrace_defld = "ld"; /* default ld(1) to invoke */ const char *_dtrace_defobjcopy = "objcopy"; /* default objcopy(1) to invoke */ #endif const char *_dtrace_libdir = "/usr/lib/dtrace"; /* default library directory */ #ifdef illumos const char *_dtrace_provdir = "/dev/dtrace/provider"; /* provider directory */ #else const char *_dtrace_libdir32 = "/usr/lib32/dtrace"; const char *_dtrace_provdir = "/dev/dtrace"; /* provider directory */ #endif int _dtrace_strbuckets = 211; /* default number of hash buckets (prime) */ int _dtrace_intbuckets = 256; /* default number of integer buckets (Pof2) */ uint_t _dtrace_strsize = 256; /* default size of string intrinsic type */ uint_t _dtrace_stkindent = 14; /* default whitespace indent for stack/ustack */ uint_t _dtrace_pidbuckets = 64; /* default number of pid hash buckets */ uint_t _dtrace_pidlrulim = 8; /* default number of pid handles to cache */ size_t _dtrace_bufsize = 512; /* default dt_buf_create() size */ int _dtrace_argmax = 32; /* default maximum number of probe arguments */ int _dtrace_debug = 0; /* debug messages enabled (off) */ const char *const _dtrace_version = DT_VERS_STRING; /* API version string */ int _dtrace_rdvers = RD_VERSION; /* rtld_db feature version */ typedef struct dt_fdlist { int *df_fds; /* array of provider driver file descriptors */ uint_t df_ents; /* number of valid elements in df_fds[] */ uint_t df_size; /* size of df_fds[] */ } dt_fdlist_t; #ifdef illumos #pragma init(_dtrace_init) #else void _dtrace_init(void) __attribute__ ((constructor)); #endif void _dtrace_init(void) { _dtrace_debug = getenv("DTRACE_DEBUG") != NULL; for (; _dtrace_rdvers > 0; _dtrace_rdvers--) { if (rd_init(_dtrace_rdvers) == RD_OK) break; } #if defined(__i386__) /* make long doubles 64 bits -sson */ (void) fpsetprec(FP_PE); #endif } static dtrace_hdl_t * set_open_errno(dtrace_hdl_t *dtp, int *errp, int err) { if (dtp != NULL) dtrace_close(dtp); if (errp != NULL) *errp = err; return (NULL); } static void dt_provmod_open(dt_provmod_t **provmod, dt_fdlist_t *dfp) { dt_provmod_t *prov; char path[PATH_MAX]; int fd; #ifdef illumos struct dirent *dp, *ep; DIR *dirp; if ((dirp = opendir(_dtrace_provdir)) == NULL) return; /* failed to open directory; just skip it */ ep = alloca(sizeof (struct dirent) + PATH_MAX + 1); bzero(ep, sizeof (struct dirent) + PATH_MAX + 1); while (readdir_r(dirp, ep, &dp) == 0 && dp != NULL) { if (dp->d_name[0] == '.') continue; /* skip "." and ".." */ if (dfp->df_ents == dfp->df_size) { uint_t size = dfp->df_size ? dfp->df_size * 2 : 16; int *fds = realloc(dfp->df_fds, size * sizeof (int)); if (fds == NULL) break; /* skip the rest of this directory */ dfp->df_fds = fds; dfp->df_size = size; } (void) snprintf(path, sizeof (path), "%s/%s", _dtrace_provdir, dp->d_name); if ((fd = open(path, O_RDONLY)) == -1) continue; /* failed to open driver; just skip it */ if (((prov = malloc(sizeof (dt_provmod_t))) == NULL) || (prov->dp_name = malloc(strlen(dp->d_name) + 1)) == NULL) { free(prov); (void) close(fd); break; } (void) strcpy(prov->dp_name, dp->d_name); prov->dp_next = *provmod; *provmod = prov; dt_dprintf("opened provider %s\n", dp->d_name); dfp->df_fds[dfp->df_ents++] = fd; } (void) closedir(dirp); #else /* !illumos */ char *p; char *p1; char *p_providers = NULL; int error; size_t len = 0; /* * Loop to allocate/reallocate memory for the string of provider * names and retry: */ while(1) { /* * The first time around, get the string length. The next time, * hopefully we've allocated enough memory. */ error = sysctlbyname("debug.dtrace.providers",p_providers,&len,NULL,0); if (len == 0) /* No providers? That's strange. Where's dtrace? */ break; else if (error == 0 && p_providers == NULL) { /* * Allocate the initial memory which should be enough * unless another provider loads before we have * time to go back and get the string. */ if ((p_providers = malloc(len)) == NULL) /* How do we report errors here? */ return; } else if (error == -1 && errno == ENOMEM) { /* * The current buffer isn't large enough, so * reallocate it. We normally won't need to do this * because providers aren't being loaded all the time. */ if ((p = realloc(p_providers,len)) == NULL) { free(p_providers); /* How do we report errors here? */ return; } p_providers = p; } else break; } /* Check if we got a string of provider names: */ if (error == 0 && len > 0 && p_providers != NULL) { p = p_providers; /* * Parse the string containing the space separated * provider names. */ while ((p1 = strsep(&p," ")) != NULL) { if (dfp->df_ents == dfp->df_size) { uint_t size = dfp->df_size ? dfp->df_size * 2 : 16; int *fds = realloc(dfp->df_fds, size * sizeof (int)); if (fds == NULL) break; dfp->df_fds = fds; dfp->df_size = size; } (void) snprintf(path, sizeof (path), "/dev/dtrace/%s", p1); if ((fd = open(path, O_RDONLY | O_CLOEXEC)) == -1) continue; /* failed to open driver; just skip it */ if (((prov = malloc(sizeof (dt_provmod_t))) == NULL) || (prov->dp_name = malloc(strlen(p1) + 1)) == NULL) { free(prov); (void) close(fd); break; } (void) strcpy(prov->dp_name, p1); prov->dp_next = *provmod; *provmod = prov; dt_dprintf("opened provider %s\n", p1); dfp->df_fds[dfp->df_ents++] = fd; } } if (p_providers != NULL) free(p_providers); #endif /* illumos */ } static void dt_provmod_destroy(dt_provmod_t **provmod) { dt_provmod_t *next, *current; for (current = *provmod; current != NULL; current = next) { next = current->dp_next; free(current->dp_name); free(current); } *provmod = NULL; } #ifdef illumos static const char * dt_get_sysinfo(int cmd, char *buf, size_t len) { ssize_t rv = sysinfo(cmd, buf, len); char *p = buf; if (rv < 0 || rv > len) (void) snprintf(buf, len, "%s", "Unknown"); while ((p = strchr(p, '.')) != NULL) *p++ = '_'; return (buf); } #endif static dtrace_hdl_t * dt_vopen(int version, int flags, int *errp, const dtrace_vector_t *vector, void *arg) { dtrace_hdl_t *dtp = NULL; int dtfd = -1, ftfd = -1, fterr = 0; dtrace_prog_t *pgp; dt_module_t *dmp; dt_provmod_t *provmod = NULL; int i, err; struct rlimit rl; const dt_intrinsic_t *dinp; const dt_typedef_t *dtyp; const dt_ident_t *idp; dtrace_typeinfo_t dtt; ctf_funcinfo_t ctc; ctf_arinfo_t ctr; dt_fdlist_t df = { NULL, 0, 0 }; char isadef[32], utsdef[32]; char s1[64], s2[64]; if (version <= 0) return (set_open_errno(dtp, errp, EINVAL)); if (version > DTRACE_VERSION) return (set_open_errno(dtp, errp, EDT_VERSION)); if (version < DTRACE_VERSION) { /* * Currently, increasing the library version number is used to * denote a binary incompatible change. That is, a consumer * of the library cannot run on a version of the library with * a higher DTRACE_VERSION number than the consumer compiled * against. Once the library API has been committed to, * backwards binary compatibility will be required; at that * time, this check should change to return EDT_OVERSION only * if the specified version number is less than the version * number at the time of interface commitment. */ return (set_open_errno(dtp, errp, EDT_OVERSION)); } if (flags & ~DTRACE_O_MASK) return (set_open_errno(dtp, errp, EINVAL)); if ((flags & DTRACE_O_LP64) && (flags & DTRACE_O_ILP32)) return (set_open_errno(dtp, errp, EINVAL)); if (vector == NULL && arg != NULL) return (set_open_errno(dtp, errp, EINVAL)); if (elf_version(EV_CURRENT) == EV_NONE) return (set_open_errno(dtp, errp, EDT_ELFVERSION)); if (vector != NULL || (flags & DTRACE_O_NODEV)) goto alloc; /* do not attempt to open dtrace device */ /* * Before we get going, crank our limit on file descriptors up to the * hard limit. This is to allow for the fact that libproc keeps file * descriptors to objects open for the lifetime of the proc handle; * without raising our hard limit, we would have an acceptably small * bound on the number of processes that we could concurrently * instrument with the pid provider. */ if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { rl.rlim_cur = rl.rlim_max; (void) setrlimit(RLIMIT_NOFILE, &rl); } /* * Get the device path of each of the providers. We hold them open * in the df.df_fds list until we open the DTrace driver itself, * allowing us to see all of the probes provided on this system. Once * we have the DTrace driver open, we can safely close all the providers * now that they have registered with the framework. */ dt_provmod_open(&provmod, &df); dtfd = open("/dev/dtrace/dtrace", O_RDWR | O_CLOEXEC); err = dtfd == -1 ? errno : 0; /* save errno from opening dtfd */ #if defined(__FreeBSD__) /* * Automatically load the 'dtraceall' module if we couldn't open the * char device. */ if (err == ENOENT && modfind("dtraceall") < 0) { kldload("dtraceall"); /* ignore the error */ dtfd = open("/dev/dtrace/dtrace", O_RDWR | O_CLOEXEC); err = errno; } #endif #ifdef illumos ftfd = open("/dev/dtrace/provider/fasttrap", O_RDWR); #else ftfd = open("/dev/dtrace/fasttrap", O_RDWR | O_CLOEXEC); #endif fterr = ftfd == -1 ? errno : 0; /* save errno from open ftfd */ while (df.df_ents-- != 0) (void) close(df.df_fds[df.df_ents]); free(df.df_fds); /* * If we failed to open the dtrace device, fail dtrace_open(). * We convert some kernel errnos to custom libdtrace errnos to * improve the resulting message from the usual strerror(). */ if (dtfd == -1) { dt_provmod_destroy(&provmod); switch (err) { case ENOENT: err = EDT_NOENT; break; case EBUSY: err = EDT_BUSY; break; case EACCES: err = EDT_ACCESS; break; } return (set_open_errno(dtp, errp, err)); } alloc: if ((dtp = malloc(sizeof (dtrace_hdl_t))) == NULL) { dt_provmod_destroy(&provmod); return (set_open_errno(dtp, errp, EDT_NOMEM)); } bzero(dtp, sizeof (dtrace_hdl_t)); dtp->dt_oflags = flags; #ifdef illumos dtp->dt_prcmode = DT_PROC_STOP_PREINIT; #else dtp->dt_prcmode = DT_PROC_STOP_POSTINIT; #endif dtp->dt_linkmode = DT_LINK_KERNEL; dtp->dt_linktype = DT_LTYP_ELF; dtp->dt_xlatemode = DT_XL_STATIC; dtp->dt_stdcmode = DT_STDC_XA; dtp->dt_encoding = DT_ENCODING_UNSET; dtp->dt_version = version; dtp->dt_fd = dtfd; dtp->dt_ftfd = ftfd; + dtp->dt_kinstfd = -1; dtp->dt_fterr = fterr; dtp->dt_cdefs_fd = -1; dtp->dt_ddefs_fd = -1; #ifdef illumos dtp->dt_stdout_fd = -1; #else dtp->dt_freopen_fp = NULL; #endif dtp->dt_modbuckets = _dtrace_strbuckets; dtp->dt_mods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *)); #ifdef __FreeBSD__ dtp->dt_kmods = calloc(dtp->dt_modbuckets, sizeof (dt_module_t *)); #endif dtp->dt_provbuckets = _dtrace_strbuckets; dtp->dt_provs = calloc(dtp->dt_provbuckets, sizeof (dt_provider_t *)); dt_proc_init(dtp); dtp->dt_vmax = DT_VERS_LATEST; dtp->dt_cpp_path = strdup(_dtrace_defcpp); dtp->dt_cpp_argv = malloc(sizeof (char *)); dtp->dt_cpp_argc = 1; dtp->dt_cpp_args = 1; dtp->dt_ld_path = strdup(_dtrace_defld); #ifdef __FreeBSD__ dtp->dt_objcopy_path = strdup(_dtrace_defobjcopy); #endif dtp->dt_provmod = provmod; dtp->dt_vector = vector; dtp->dt_varg = arg; dt_dof_init(dtp); (void) uname(&dtp->dt_uts); if (dtp->dt_mods == NULL || dtp->dt_provs == NULL || dtp->dt_procs == NULL || dtp->dt_proc_env == NULL || dtp->dt_ld_path == NULL || dtp->dt_cpp_path == NULL || #ifdef __FreeBSD__ dtp->dt_kmods == NULL || dtp->dt_objcopy_path == NULL || #endif dtp->dt_cpp_argv == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); for (i = 0; i < DTRACEOPT_MAX; i++) dtp->dt_options[i] = DTRACEOPT_UNSET; dtp->dt_cpp_argv[0] = (char *)strbasename(dtp->dt_cpp_path); #ifdef illumos (void) snprintf(isadef, sizeof (isadef), "-D__SUNW_D_%u", (uint_t)(sizeof (void *) * NBBY)); (void) snprintf(utsdef, sizeof (utsdef), "-D__%s_%s", dt_get_sysinfo(SI_SYSNAME, s1, sizeof (s1)), dt_get_sysinfo(SI_RELEASE, s2, sizeof (s2))); if (dt_cpp_add_arg(dtp, "-D__sun") == NULL || dt_cpp_add_arg(dtp, "-D__unix") == NULL || dt_cpp_add_arg(dtp, "-D__SVR4") == NULL || dt_cpp_add_arg(dtp, "-D__SUNW_D=1") == NULL || dt_cpp_add_arg(dtp, isadef) == NULL || dt_cpp_add_arg(dtp, utsdef) == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); #endif if (flags & DTRACE_O_NODEV) bcopy(&_dtrace_conf, &dtp->dt_conf, sizeof (_dtrace_conf)); else if (dt_ioctl(dtp, DTRACEIOC_CONF, &dtp->dt_conf) != 0) return (set_open_errno(dtp, errp, errno)); if (flags & DTRACE_O_LP64) dtp->dt_conf.dtc_ctfmodel = CTF_MODEL_LP64; else if (flags & DTRACE_O_ILP32) dtp->dt_conf.dtc_ctfmodel = CTF_MODEL_ILP32; #ifdef __sparc /* * On SPARC systems, __sparc is always defined for * and __sparcv9 is defined if we are doing a 64-bit compile. */ if (dt_cpp_add_arg(dtp, "-D__sparc") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64 && dt_cpp_add_arg(dtp, "-D__sparcv9") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); #endif #ifdef illumos #ifdef __x86 /* * On x86 systems, __i386 is defined for for 32-bit * compiles and __amd64 is defined for 64-bit compiles. Unlike SPARC, * they are defined exclusive of one another (see PSARC 2004/619). */ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) { if (dt_cpp_add_arg(dtp, "-D__amd64") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); } else { if (dt_cpp_add_arg(dtp, "-D__i386") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); } #endif #else #if defined(__amd64__) || defined(__i386__) if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) { if (dt_cpp_add_arg(dtp, "-m64") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); } else { if (dt_cpp_add_arg(dtp, "-m32") == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); } #endif #endif if (dtp->dt_conf.dtc_difversion < DIF_VERSION) return (set_open_errno(dtp, errp, EDT_DIFVERS)); if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_ILP32) bcopy(_dtrace_ints_32, dtp->dt_ints, sizeof (_dtrace_ints_32)); else bcopy(_dtrace_ints_64, dtp->dt_ints, sizeof (_dtrace_ints_64)); /* * On FreeBSD the kernel module name can't be hard-coded. The * 'kern.bootfile' sysctl value tells us exactly which file is being * used as the kernel. */ #ifndef illumos { char bootfile[MAXPATHLEN]; char *p; int i; size_t len = sizeof(bootfile); /* This call shouldn't fail, but use a default just in case. */ if (sysctlbyname("kern.bootfile", bootfile, &len, NULL, 0) != 0) strlcpy(bootfile, "kernel", sizeof(bootfile)); if ((p = strrchr(bootfile, '/')) != NULL) p++; else p = bootfile; /* * Format the global variables based on the kernel module name. */ snprintf(curthread_str, sizeof(curthread_str), "%s`struct thread *",p); snprintf(intmtx_str, sizeof(intmtx_str), "int(%s`struct mtx *)",p); snprintf(threadmtx_str, sizeof(threadmtx_str), "struct thread *(%s`struct mtx *)",p); snprintf(rwlock_str, sizeof(rwlock_str), "int(%s`struct rwlock *)",p); snprintf(sxlock_str, sizeof(sxlock_str), "int(%s`struct sx *)",p); } #endif dtp->dt_macros = dt_idhash_create("macro", NULL, 0, UINT_MAX); dtp->dt_aggs = dt_idhash_create("aggregation", NULL, DTRACE_AGGVARIDNONE + 1, UINT_MAX); dtp->dt_globals = dt_idhash_create("global", _dtrace_globals, DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX); dtp->dt_tls = dt_idhash_create("thread local", NULL, DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX); if (dtp->dt_macros == NULL || dtp->dt_aggs == NULL || dtp->dt_globals == NULL || dtp->dt_tls == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); /* * Populate the dt_macros identifier hash table by hand: we can't use * the dt_idhash_populate() mechanism because we're not yet compiling * and dtrace_update() needs to immediately reference these idents. */ for (idp = _dtrace_macros; idp->di_name != NULL; idp++) { if (dt_idhash_insert(dtp->dt_macros, idp->di_name, idp->di_kind, idp->di_flags, idp->di_id, idp->di_attr, idp->di_vers, idp->di_ops ? idp->di_ops : &dt_idops_thaw, idp->di_iarg, 0) == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); } /* * Update the module list using /system/object and load the values for * the macro variable definitions according to the current process. */ dtrace_update(dtp); /* * Select the intrinsics and typedefs we want based on the data model. * The intrinsics are under "C". The typedefs are added under "D". */ if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_ILP32) { dinp = _dtrace_intrinsics_32; dtyp = _dtrace_typedefs_32; } else { dinp = _dtrace_intrinsics_64; dtyp = _dtrace_typedefs_64; } /* * Create a dynamic CTF container under the "C" scope for intrinsic * types and types defined in ANSI-C header files that are included. */ if ((dmp = dtp->dt_cdefs = dt_module_create(dtp, "C")) == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); if ((dmp->dm_ctfp = ctf_create(&dtp->dt_ctferr)) == NULL) return (set_open_errno(dtp, errp, EDT_CTF)); dt_dprintf("created CTF container for %s (%p)\n", dmp->dm_name, (void *)dmp->dm_ctfp); (void) ctf_setmodel(dmp->dm_ctfp, dtp->dt_conf.dtc_ctfmodel); ctf_setspecific(dmp->dm_ctfp, dmp); dmp->dm_flags = DT_DM_LOADED; /* fake up loaded bit */ dmp->dm_modid = -1; /* no module ID */ /* * Fill the dynamic "C" CTF container with all of the intrinsic * integer and floating-point types appropriate for this data model. */ for (; dinp->din_name != NULL; dinp++) { if (dinp->din_kind == CTF_K_INTEGER) { err = ctf_add_integer(dmp->dm_ctfp, CTF_ADD_ROOT, dinp->din_name, &dinp->din_data); } else { err = ctf_add_float(dmp->dm_ctfp, CTF_ADD_ROOT, dinp->din_name, &dinp->din_data); } if (err == CTF_ERR) { dt_dprintf("failed to add %s to C container: %s\n", dinp->din_name, ctf_errmsg( ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } } if (ctf_update(dmp->dm_ctfp) != 0) { dt_dprintf("failed to update C container: %s\n", ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } /* * Add intrinsic pointer types that are needed to initialize printf * format dictionary types (see table in dt_printf.c). */ (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, ctf_lookup_by_name(dmp->dm_ctfp, "void")); (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, ctf_lookup_by_name(dmp->dm_ctfp, "char")); (void) ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, ctf_lookup_by_name(dmp->dm_ctfp, "int")); if (ctf_update(dmp->dm_ctfp) != 0) { dt_dprintf("failed to update C container: %s\n", ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } /* * Create a dynamic CTF container under the "D" scope for types that * are defined by the D program itself or on-the-fly by the D compiler. * The "D" CTF container is a child of the "C" CTF container. */ if ((dmp = dtp->dt_ddefs = dt_module_create(dtp, "D")) == NULL) return (set_open_errno(dtp, errp, EDT_NOMEM)); if ((dmp->dm_ctfp = ctf_create(&dtp->dt_ctferr)) == NULL) return (set_open_errno(dtp, errp, EDT_CTF)); dt_dprintf("created CTF container for %s (%p)\n", dmp->dm_name, (void *)dmp->dm_ctfp); (void) ctf_setmodel(dmp->dm_ctfp, dtp->dt_conf.dtc_ctfmodel); ctf_setspecific(dmp->dm_ctfp, dmp); dmp->dm_flags = DT_DM_LOADED; /* fake up loaded bit */ dmp->dm_modid = -1; /* no module ID */ if (ctf_import(dmp->dm_ctfp, dtp->dt_cdefs->dm_ctfp) == CTF_ERR) { dt_dprintf("failed to import D parent container: %s\n", ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } /* * Fill the dynamic "D" CTF container with all of the built-in typedefs * that we need to use for our D variable and function definitions. * This ensures that basic inttypes.h names are always available to us. */ for (; dtyp->dty_src != NULL; dtyp++) { if (ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, dtyp->dty_dst, ctf_lookup_by_name(dmp->dm_ctfp, dtyp->dty_src)) == CTF_ERR) { dt_dprintf("failed to add typedef %s %s to D " "container: %s\n", dtyp->dty_src, dtyp->dty_dst, ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } } /* * Insert a CTF ID corresponding to a pointer to a type of kind * CTF_K_FUNCTION we can use in the compiler for function pointers. * CTF treats all function pointers as "int (*)()" so we only need one. */ ctc.ctc_return = ctf_lookup_by_name(dmp->dm_ctfp, "int"); ctc.ctc_argc = 0; ctc.ctc_flags = 0; dtp->dt_type_func = ctf_add_function(dmp->dm_ctfp, CTF_ADD_ROOT, &ctc, NULL); dtp->dt_type_fptr = ctf_add_pointer(dmp->dm_ctfp, CTF_ADD_ROOT, dtp->dt_type_func); /* * We also insert CTF definitions for the special D intrinsic types * string and into the D container. The string type is added * as a typedef of char[n]. The type is an alias for void. * We compare types to these special CTF ids throughout the compiler. */ ctr.ctr_contents = ctf_lookup_by_name(dmp->dm_ctfp, "char"); ctr.ctr_index = ctf_lookup_by_name(dmp->dm_ctfp, "long"); ctr.ctr_nelems = _dtrace_strsize; dtp->dt_type_str = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "string", ctf_add_array(dmp->dm_ctfp, CTF_ADD_ROOT, &ctr)); dtp->dt_type_dyn = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "", ctf_lookup_by_name(dmp->dm_ctfp, "void")); dtp->dt_type_stack = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "stack", ctf_lookup_by_name(dmp->dm_ctfp, "void")); dtp->dt_type_symaddr = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "_symaddr", ctf_lookup_by_name(dmp->dm_ctfp, "void")); dtp->dt_type_usymaddr = ctf_add_typedef(dmp->dm_ctfp, CTF_ADD_ROOT, "_usymaddr", ctf_lookup_by_name(dmp->dm_ctfp, "void")); if (dtp->dt_type_func == CTF_ERR || dtp->dt_type_fptr == CTF_ERR || dtp->dt_type_str == CTF_ERR || dtp->dt_type_dyn == CTF_ERR || dtp->dt_type_stack == CTF_ERR || dtp->dt_type_symaddr == CTF_ERR || dtp->dt_type_usymaddr == CTF_ERR) { dt_dprintf("failed to add intrinsic to D container: %s\n", ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } if (ctf_update(dmp->dm_ctfp) != 0) { dt_dprintf("failed update D container: %s\n", ctf_errmsg(ctf_errno(dmp->dm_ctfp))); return (set_open_errno(dtp, errp, EDT_CTF)); } /* * Initialize the integer description table used to convert integer * constants to the appropriate types. Refer to the comments above * dt_node_int() for a complete description of how this table is used. */ for (i = 0; i < sizeof (dtp->dt_ints) / sizeof (dtp->dt_ints[0]); i++) { if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_EVERY, dtp->dt_ints[i].did_name, &dtt) != 0) { dt_dprintf("failed to lookup integer type %s: %s\n", dtp->dt_ints[i].did_name, dtrace_errmsg(dtp, dtrace_errno(dtp))); return (set_open_errno(dtp, errp, dtp->dt_errno)); } dtp->dt_ints[i].did_ctfp = dtt.dtt_ctfp; dtp->dt_ints[i].did_type = dtt.dtt_type; } /* * Now that we've created the "C" and "D" containers, move them to the * start of the module list so that these types and symbols are found * first (for stability) when iterating through the module list. */ dt_list_delete(&dtp->dt_modlist, dtp->dt_ddefs); dt_list_prepend(&dtp->dt_modlist, dtp->dt_ddefs); dt_list_delete(&dtp->dt_modlist, dtp->dt_cdefs); dt_list_prepend(&dtp->dt_modlist, dtp->dt_cdefs); if (dt_pfdict_create(dtp) == -1) return (set_open_errno(dtp, errp, dtp->dt_errno)); /* * If we are opening libdtrace DTRACE_O_NODEV enable C_ZDEFS by default * because without /dev/dtrace open, we will not be able to load the * names and attributes of any providers or probes from the kernel. */ if (flags & DTRACE_O_NODEV) dtp->dt_cflags |= DTRACE_C_ZDEFS; /* * Load hard-wired inlines into the definition cache by calling the * compiler on the raw definition string defined above. */ if ((pgp = dtrace_program_strcompile(dtp, _dtrace_hardwire, DTRACE_PROBESPEC_NONE, DTRACE_C_EMPTY, 0, NULL)) == NULL) { dt_dprintf("failed to load hard-wired definitions: %s\n", dtrace_errmsg(dtp, dtrace_errno(dtp))); return (set_open_errno(dtp, errp, EDT_HARDWIRE)); } dt_program_destroy(dtp, pgp); /* * Set up the default DTrace library path. Once set, the next call to * dt_compile() will compile all the libraries. We intentionally defer * library processing to improve overhead for clients that don't ever * compile, and to provide better error reporting (because the full * reporting of compiler errors requires dtrace_open() to succeed). */ #ifdef __FreeBSD__ #ifdef __LP64__ if ((dtp->dt_oflags & DTRACE_O_ILP32) != 0) { if (dtrace_setopt(dtp, "libdir", _dtrace_libdir32) != 0) return (set_open_errno(dtp, errp, dtp->dt_errno)); } #endif if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0) return (set_open_errno(dtp, errp, dtp->dt_errno)); #else if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0) return (set_open_errno(dtp, errp, dtp->dt_errno)); #endif return (dtp); } dtrace_hdl_t * dtrace_open(int version, int flags, int *errp) { return (dt_vopen(version, flags, errp, NULL, NULL)); } dtrace_hdl_t * dtrace_vopen(int version, int flags, int *errp, const dtrace_vector_t *vector, void *arg) { return (dt_vopen(version, flags, errp, vector, arg)); } void dtrace_close(dtrace_hdl_t *dtp) { dt_ident_t *idp, *ndp; dt_module_t *dmp; dt_provider_t *pvp; dtrace_prog_t *pgp; dt_xlator_t *dxp; dt_dirpath_t *dirp; #ifdef __FreeBSD__ dt_kmodule_t *dkm; uint_t h; #endif int i; if (dtp->dt_procs != NULL) dt_proc_fini(dtp); while ((pgp = dt_list_next(&dtp->dt_programs)) != NULL) dt_program_destroy(dtp, pgp); while ((dxp = dt_list_next(&dtp->dt_xlators)) != NULL) dt_xlator_destroy(dtp, dxp); dt_free(dtp, dtp->dt_xlatormap); for (idp = dtp->dt_externs; idp != NULL; idp = ndp) { ndp = idp->di_next; dt_ident_destroy(idp); } if (dtp->dt_macros != NULL) dt_idhash_destroy(dtp->dt_macros); if (dtp->dt_aggs != NULL) dt_idhash_destroy(dtp->dt_aggs); if (dtp->dt_globals != NULL) dt_idhash_destroy(dtp->dt_globals); if (dtp->dt_tls != NULL) dt_idhash_destroy(dtp->dt_tls); #ifdef __FreeBSD__ for (h = 0; h < dtp->dt_modbuckets; h++) while ((dkm = dtp->dt_kmods[h]) != NULL) { dtp->dt_kmods[h] = dkm->dkm_next; free(dkm->dkm_name); free(dkm); } #endif while ((dmp = dt_list_next(&dtp->dt_modlist)) != NULL) dt_module_destroy(dtp, dmp); while ((pvp = dt_list_next(&dtp->dt_provlist)) != NULL) dt_provider_destroy(dtp, pvp); if (dtp->dt_fd != -1) (void) close(dtp->dt_fd); if (dtp->dt_ftfd != -1) (void) close(dtp->dt_ftfd); + if (dtp->dt_kinstfd != -1) + (void) close(dtp->dt_kinstfd); if (dtp->dt_cdefs_fd != -1) (void) close(dtp->dt_cdefs_fd); if (dtp->dt_ddefs_fd != -1) (void) close(dtp->dt_ddefs_fd); #ifdef illumos if (dtp->dt_stdout_fd != -1) (void) close(dtp->dt_stdout_fd); #else if (dtp->dt_freopen_fp != NULL) (void) fclose(dtp->dt_freopen_fp); #endif dt_epid_destroy(dtp); dt_aggid_destroy(dtp); dt_format_destroy(dtp); dt_strdata_destroy(dtp); dt_buffered_destroy(dtp); dt_aggregate_destroy(dtp); dt_pfdict_destroy(dtp); dt_provmod_destroy(&dtp->dt_provmod); dt_dof_fini(dtp); for (i = 1; i < dtp->dt_cpp_argc; i++) free(dtp->dt_cpp_argv[i]); while ((dirp = dt_list_next(&dtp->dt_lib_path)) != NULL) { dt_list_delete(&dtp->dt_lib_path, dirp); free(dirp->dir_path); free(dirp); } free(dtp->dt_cpp_argv); free(dtp->dt_cpp_path); free(dtp->dt_ld_path); #ifdef __FreeBSD__ free(dtp->dt_objcopy_path); #endif free(dtp->dt_mods); #ifdef __FreeBSD__ free(dtp->dt_kmods); #endif free(dtp->dt_provs); free(dtp); } int dtrace_provider_modules(dtrace_hdl_t *dtp, const char **mods, int nmods) { dt_provmod_t *prov; int i = 0; for (prov = dtp->dt_provmod; prov != NULL; prov = prov->dp_next, i++) { if (i < nmods) mods[i] = prov->dp_name; } return (i); } int dtrace_ctlfd(dtrace_hdl_t *dtp) { return (dtp->dt_fd); } diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c index 7cf352d4d505..2391690afc0b 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_provider.c @@ -1,900 +1,929 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include #ifdef illumos #include #endif #include #include #include #include #ifdef illumos #include #endif #include #include #include #include #include #include #include #include +#include static dt_provider_t * dt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp, uint_t h) { dt_list_append(&dtp->dt_provlist, pvp); pvp->pv_next = dtp->dt_provs[h]; dtp->dt_provs[h] = pvp; dtp->dt_nprovs++; return (pvp); } dt_provider_t * dt_provider_lookup(dtrace_hdl_t *dtp, const char *name) { uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_provbuckets; dtrace_providerdesc_t desc; dt_provider_t *pvp; for (pvp = dtp->dt_provs[h]; pvp != NULL; pvp = pvp->pv_next) { if (strcmp(pvp->pv_desc.dtvd_name, name) == 0) return (pvp); } if (strisglob(name) || name[0] == '\0') { (void) dt_set_errno(dtp, EDT_NOPROV); return (NULL); } bzero(&desc, sizeof (desc)); (void) strlcpy(desc.dtvd_name, name, DTRACE_PROVNAMELEN); if (dt_ioctl(dtp, DTRACEIOC_PROVIDER, &desc) == -1) { (void) dt_set_errno(dtp, errno == ESRCH ? EDT_NOPROV : errno); return (NULL); } if ((pvp = dt_provider_create(dtp, name)) == NULL) return (NULL); /* dt_errno is set for us */ bcopy(&desc, &pvp->pv_desc, sizeof (desc)); pvp->pv_flags |= DT_PROVIDER_IMPL; return (pvp); } dt_provider_t * dt_provider_create(dtrace_hdl_t *dtp, const char *name) { dt_provider_t *pvp; if ((pvp = dt_zalloc(dtp, sizeof (dt_provider_t))) == NULL) return (NULL); (void) strlcpy(pvp->pv_desc.dtvd_name, name, DTRACE_PROVNAMELEN); pvp->pv_probes = dt_idhash_create(pvp->pv_desc.dtvd_name, NULL, 0, 0); pvp->pv_gen = dtp->dt_gen; pvp->pv_hdl = dtp; if (pvp->pv_probes == NULL) { dt_free(dtp, pvp); (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } pvp->pv_desc.dtvd_attr.dtpa_provider = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_mod = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_func = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_name = _dtrace_prvattr; pvp->pv_desc.dtvd_attr.dtpa_args = _dtrace_prvattr; return (dt_provider_insert(dtp, pvp, dt_strtab_hash(name, NULL) % dtp->dt_provbuckets)); } void dt_provider_destroy(dtrace_hdl_t *dtp, dt_provider_t *pvp) { dt_provider_t **pp; uint_t h; assert(pvp->pv_hdl == dtp); h = dt_strtab_hash(pvp->pv_desc.dtvd_name, NULL) % dtp->dt_provbuckets; pp = &dtp->dt_provs[h]; while (*pp != NULL && *pp != pvp) pp = &(*pp)->pv_next; assert(*pp != NULL && *pp == pvp); *pp = pvp->pv_next; dt_list_delete(&dtp->dt_provlist, pvp); dtp->dt_nprovs--; if (pvp->pv_probes != NULL) dt_idhash_destroy(pvp->pv_probes); dt_node_link_free(&pvp->pv_nodes); dt_free(dtp, pvp->pv_xrefs); dt_free(dtp, pvp); } int dt_provider_xref(dtrace_hdl_t *dtp, dt_provider_t *pvp, id_t id) { size_t oldsize = BT_SIZEOFMAP(pvp->pv_xrmax); size_t newsize = BT_SIZEOFMAP(dtp->dt_xlatorid); assert(id >= 0 && id < dtp->dt_xlatorid); if (newsize > oldsize) { ulong_t *xrefs = dt_zalloc(dtp, newsize); if (xrefs == NULL) return (-1); bcopy(pvp->pv_xrefs, xrefs, oldsize); dt_free(dtp, pvp->pv_xrefs); pvp->pv_xrefs = xrefs; pvp->pv_xrmax = dtp->dt_xlatorid; } BT_SET(pvp->pv_xrefs, id); return (0); } static uint8_t dt_probe_argmap(dt_node_t *xnp, dt_node_t *nnp) { uint8_t i; for (i = 0; nnp != NULL; i++) { if (nnp->dn_string != NULL && strcmp(nnp->dn_string, xnp->dn_string) == 0) break; else nnp = nnp->dn_list; } return (i); } static dt_node_t * dt_probe_alloc_args(dt_provider_t *pvp, int argc) { dt_node_t *args = NULL, *pnp = NULL, *dnp; int i; for (i = 0; i < argc; i++, pnp = dnp) { if ((dnp = dt_node_xalloc(pvp->pv_hdl, DT_NODE_TYPE)) == NULL) return (NULL); dnp->dn_link = pvp->pv_nodes; pvp->pv_nodes = dnp; if (args == NULL) args = dnp; else pnp->dn_list = dnp; } return (args); } static size_t dt_probe_keylen(const dtrace_probedesc_t *pdp) { return (strlen(pdp->dtpd_mod) + 1 + strlen(pdp->dtpd_func) + 1 + strlen(pdp->dtpd_name) + 1); } static char * dt_probe_key(const dtrace_probedesc_t *pdp, char *s) { (void) snprintf(s, INT_MAX, "%s:%s:%s", pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name); return (s); } /* * If a probe was discovered from the kernel, ask dtrace(7D) for a description * of each of its arguments, including native and translated types. */ static dt_probe_t * dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp) { dtrace_hdl_t *dtp = pvp->pv_hdl; char *name = dt_probe_key(pdp, alloca(dt_probe_keylen(pdp))); dt_node_t *xargs, *nargs; dt_ident_t *idp; dt_probe_t *prp; dtrace_typeinfo_t dtt; int i, nc, xc; int adc = _dtrace_argmax; dtrace_argdesc_t *adv = alloca(sizeof (dtrace_argdesc_t) * adc); dtrace_argdesc_t *adp = adv; assert(strcmp(pvp->pv_desc.dtvd_name, pdp->dtpd_provider) == 0); assert(pdp->dtpd_id != DTRACE_IDNONE); dt_dprintf("discovering probe %s:%s id=%d\n", pvp->pv_desc.dtvd_name, name, pdp->dtpd_id); for (nc = -1, i = 0; i < adc; i++, adp++) { bzero(adp, sizeof (dtrace_argdesc_t)); adp->dtargd_ndx = i; adp->dtargd_id = pdp->dtpd_id; if (dt_ioctl(dtp, DTRACEIOC_PROBEARG, adp) != 0) { (void) dt_set_errno(dtp, errno); return (NULL); } if (adp->dtargd_ndx == DTRACE_ARGNONE) break; /* all argument descs have been retrieved */ nc = MAX(nc, adp->dtargd_mapping); } xc = i; nc++; /* * The pid provider believes in giving the kernel a break. No reason to * give the kernel all the ctf containers that we're keeping ourselves * just to get it back from it. So if we're coming from a pid provider * probe and the kernel gave us no argument information we'll get some * here. If for some crazy reason the kernel knows about our userland * types then we just ignore this. */ if (xc == 0 && nc == 0 && strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) { nc = adc; dt_pid_get_types(dtp, pdp, adv, &nc); xc = nc; } /* * Now that we have discovered the number of native and translated * arguments from the argument descriptions, allocate a new probe ident * and corresponding dt_probe_t and hash it into the provider. */ xargs = dt_probe_alloc_args(pvp, xc); nargs = dt_probe_alloc_args(pvp, nc); if ((xc != 0 && xargs == NULL) || (nc != 0 && nargs == NULL)) return (NULL); /* dt_errno is set for us */ idp = dt_ident_create(name, DT_IDENT_PROBE, DT_IDFLG_ORPHAN, pdp->dtpd_id, _dtrace_defattr, 0, &dt_idops_probe, NULL, dtp->dt_gen); if (idp == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } if ((prp = dt_probe_create(dtp, idp, 2, nargs, nc, xargs, xc)) == NULL) { dt_ident_destroy(idp); return (NULL); } dt_probe_declare(pvp, prp); /* * Once our new dt_probe_t is fully constructed, iterate over the * cached argument descriptions and assign types to prp->pr_nargv[] * and prp->pr_xargv[] and assign mappings to prp->pr_mapping[]. */ for (adp = adv, i = 0; i < xc; i++, adp++) { if (dtrace_type_strcompile(dtp, adp->dtargd_native, &dtt) != 0) { dt_dprintf("failed to resolve input type %s " "for %s:%s arg #%d: %s\n", adp->dtargd_native, pvp->pv_desc.dtvd_name, name, i + 1, dtrace_errmsg(dtp, dtrace_errno(dtp))); dtt.dtt_object = NULL; dtt.dtt_ctfp = NULL; dtt.dtt_type = CTF_ERR; } else { dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping], dtt.dtt_ctfp, dtt.dtt_type, dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE); } if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' || strcmp(adp->dtargd_native, adp->dtargd_xlate) == 0)) { dt_node_type_propagate(prp->pr_nargv[ adp->dtargd_mapping], prp->pr_xargv[i]); } else if (dtrace_type_strcompile(dtp, adp->dtargd_xlate, &dtt) != 0) { dt_dprintf("failed to resolve output type %s " "for %s:%s arg #%d: %s\n", adp->dtargd_xlate, pvp->pv_desc.dtvd_name, name, i + 1, dtrace_errmsg(dtp, dtrace_errno(dtp))); dtt.dtt_object = NULL; dtt.dtt_ctfp = NULL; dtt.dtt_type = CTF_ERR; } else { dt_node_type_assign(prp->pr_xargv[i], dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); } prp->pr_mapping[i] = adp->dtargd_mapping; prp->pr_argv[i] = dtt; } return (prp); } /* * Lookup a probe declaration based on a known provider and full or partially * specified module, function, and name. If the probe is not known to us yet, * ask dtrace(7D) to match the description and then cache any useful results. */ dt_probe_t * dt_probe_lookup(dt_provider_t *pvp, const char *s) { dtrace_hdl_t *dtp = pvp->pv_hdl; dtrace_probedesc_t pd; dt_ident_t *idp; size_t keylen; char *key; if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, s, &pd) != 0) return (NULL); /* dt_errno is set for us */ keylen = dt_probe_keylen(&pd); key = dt_probe_key(&pd, alloca(keylen)); /* * If the probe is already declared, then return the dt_probe_t from * the existing identifier. This could come from a static declaration * or it could have been cached from an earlier call to this function. */ if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL) return (idp->di_data); /* * If the probe isn't known, use the probe description computed above * to ask dtrace(7D) to find the first matching probe. */ if (dt_ioctl(dtp, DTRACEIOC_PROBEMATCH, &pd) == 0) return (dt_probe_discover(pvp, &pd)); if (errno == ESRCH || errno == EBADF) (void) dt_set_errno(dtp, EDT_NOPROBE); else (void) dt_set_errno(dtp, errno); return (NULL); } dt_probe_t * dt_probe_create(dtrace_hdl_t *dtp, dt_ident_t *idp, int protoc, dt_node_t *nargs, uint_t nargc, dt_node_t *xargs, uint_t xargc) { dt_module_t *dmp; dt_probe_t *prp; const char *p; uint_t i; assert(idp->di_kind == DT_IDENT_PROBE); assert(idp->di_data == NULL); /* * If only a single prototype is given, set xargc/s to nargc/s to * simplify subsequent use. Note that we can have one or both of nargs * and xargs be specified but set to NULL, indicating a void prototype. */ if (protoc < 2) { assert(xargs == NULL); assert(xargc == 0); xargs = nargs; xargc = nargc; } if ((prp = dt_alloc(dtp, sizeof (dt_probe_t))) == NULL) return (NULL); prp->pr_pvp = NULL; prp->pr_ident = idp; p = strrchr(idp->di_name, ':'); assert(p != NULL); prp->pr_name = p + 1; prp->pr_nargs = nargs; prp->pr_nargv = dt_alloc(dtp, sizeof (dt_node_t *) * nargc); prp->pr_nargc = nargc; prp->pr_xargs = xargs; prp->pr_xargv = dt_alloc(dtp, sizeof (dt_node_t *) * xargc); prp->pr_xargc = xargc; prp->pr_mapping = dt_alloc(dtp, sizeof (uint8_t) * xargc); prp->pr_inst = NULL; prp->pr_argv = dt_alloc(dtp, sizeof (dtrace_typeinfo_t) * xargc); prp->pr_argc = xargc; if ((prp->pr_nargc != 0 && prp->pr_nargv == NULL) || (prp->pr_xargc != 0 && prp->pr_xargv == NULL) || (prp->pr_xargc != 0 && prp->pr_mapping == NULL) || (prp->pr_argc != 0 && prp->pr_argv == NULL)) { dt_probe_destroy(prp); return (NULL); } for (i = 0; i < xargc; i++, xargs = xargs->dn_list) { if (xargs->dn_string != NULL) prp->pr_mapping[i] = dt_probe_argmap(xargs, nargs); else prp->pr_mapping[i] = i; prp->pr_xargv[i] = xargs; if ((dmp = dt_module_lookup_by_ctf(dtp, xargs->dn_ctfp)) != NULL) prp->pr_argv[i].dtt_object = dmp->dm_name; else prp->pr_argv[i].dtt_object = NULL; prp->pr_argv[i].dtt_ctfp = xargs->dn_ctfp; prp->pr_argv[i].dtt_type = xargs->dn_type; } for (i = 0; i < nargc; i++, nargs = nargs->dn_list) prp->pr_nargv[i] = nargs; idp->di_data = prp; return (prp); } void dt_probe_declare(dt_provider_t *pvp, dt_probe_t *prp) { assert(prp->pr_ident->di_kind == DT_IDENT_PROBE); assert(prp->pr_ident->di_data == prp); assert(prp->pr_pvp == NULL); if (prp->pr_xargs != prp->pr_nargs) pvp->pv_flags &= ~DT_PROVIDER_INTF; prp->pr_pvp = pvp; dt_idhash_xinsert(pvp->pv_probes, prp->pr_ident); } void dt_probe_destroy(dt_probe_t *prp) { dt_probe_instance_t *pip, *pip_next; dtrace_hdl_t *dtp; if (prp->pr_pvp != NULL) dtp = prp->pr_pvp->pv_hdl; else dtp = yypcb->pcb_hdl; dt_node_list_free(&prp->pr_nargs); dt_node_list_free(&prp->pr_xargs); dt_free(dtp, prp->pr_nargv); dt_free(dtp, prp->pr_xargv); for (pip = prp->pr_inst; pip != NULL; pip = pip_next) { pip_next = pip->pi_next; dt_free(dtp, pip->pi_rname); dt_free(dtp, pip->pi_fname); dt_free(dtp, pip->pi_offs); dt_free(dtp, pip->pi_enoffs); dt_free(dtp, pip); } dt_free(dtp, prp->pr_mapping); dt_free(dtp, prp->pr_argv); dt_free(dtp, prp); } int dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp, const char *fname, const char *rname, uint32_t offset, int isenabled) { dtrace_hdl_t *dtp = pvp->pv_hdl; dt_probe_instance_t *pip; uint32_t **offs; uint_t *noffs, *maxoffs; assert(fname != NULL); for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) { if (strcmp(pip->pi_fname, fname) == 0 && strcmp(pip->pi_rname, rname) == 0) break; } if (pip == NULL) { if ((pip = dt_zalloc(dtp, sizeof (*pip))) == NULL) return (-1); if ((pip->pi_offs = dt_zalloc(dtp, sizeof (uint32_t))) == NULL) goto nomem; if ((pip->pi_enoffs = dt_zalloc(dtp, sizeof (uint32_t))) == NULL) goto nomem; if ((pip->pi_fname = strdup(fname)) == NULL) goto nomem; if ((pip->pi_rname = strdup(rname)) == NULL) goto nomem; pip->pi_noffs = 0; pip->pi_maxoffs = 1; pip->pi_nenoffs = 0; pip->pi_maxenoffs = 1; pip->pi_next = prp->pr_inst; prp->pr_inst = pip; } if (isenabled) { offs = &pip->pi_enoffs; noffs = &pip->pi_nenoffs; maxoffs = &pip->pi_maxenoffs; } else { offs = &pip->pi_offs; noffs = &pip->pi_noffs; maxoffs = &pip->pi_maxoffs; } if (*noffs == *maxoffs) { uint_t new_max = *maxoffs * 2; uint32_t *new_offs = dt_alloc(dtp, sizeof (uint32_t) * new_max); if (new_offs == NULL) return (-1); bcopy(*offs, new_offs, sizeof (uint32_t) * *maxoffs); dt_free(dtp, *offs); *maxoffs = new_max; *offs = new_offs; } dt_dprintf("defined probe %s %s:%s %s() +0x%x (%s)\n", isenabled ? "(is-enabled)" : "", pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, fname, offset, rname); assert(*noffs < *maxoffs); (*offs)[(*noffs)++] = offset; return (0); nomem: dt_free(dtp, pip->pi_fname); dt_free(dtp, pip->pi_enoffs); dt_free(dtp, pip->pi_offs); dt_free(dtp, pip); return (dt_set_errno(dtp, EDT_NOMEM)); } /* * Lookup the dynamic translator type tag for the specified probe argument and * assign the type to the specified node. If the type is not yet defined, add * it to the "D" module's type container as a typedef for an unknown type. */ dt_node_t * dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp) { dtrace_hdl_t *dtp = prp->pr_pvp->pv_hdl; dtrace_typeinfo_t dtt; size_t len; char *tag; len = snprintf(NULL, 0, "__dtrace_%s___%s_arg%u", prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn); tag = alloca(len + 1); (void) snprintf(tag, len + 1, "__dtrace_%s___%s_arg%u", prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn); if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_DDEFS, tag, &dtt) != 0) { dtt.dtt_object = DTRACE_OBJ_DDEFS; dtt.dtt_ctfp = DT_DYN_CTFP(dtp); dtt.dtt_type = ctf_add_typedef(DT_DYN_CTFP(dtp), CTF_ADD_ROOT, tag, DT_DYN_TYPE(dtp)); if (dtt.dtt_type == CTF_ERR || ctf_update(dtt.dtt_ctfp) == CTF_ERR) { xyerror(D_UNKNOWN, "cannot define type %s: %s\n", tag, ctf_errmsg(ctf_errno(dtt.dtt_ctfp))); } } bzero(dnp, sizeof (dt_node_t)); dnp->dn_kind = DT_NODE_TYPE; dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); dt_node_attr_assign(dnp, _dtrace_defattr); return (dnp); } /*ARGSUSED*/ static int dt_probe_desc(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg) { if (((dtrace_probedesc_t *)arg)->dtpd_id == DTRACE_IDNONE) { bcopy(pdp, arg, sizeof (dtrace_probedesc_t)); return (0); } return (1); } dt_probe_t * dt_probe_info(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip) { int m_is_glob = pdp->dtpd_mod[0] == '\0' || strisglob(pdp->dtpd_mod); int f_is_glob = pdp->dtpd_func[0] == '\0' || strisglob(pdp->dtpd_func); int n_is_glob = pdp->dtpd_name[0] == '\0' || strisglob(pdp->dtpd_name); dt_probe_t *prp = NULL; const dtrace_pattr_t *pap; dt_provider_t *pvp; dt_ident_t *idp; /* * Attempt to lookup the probe in our existing cache for this provider. * If none is found and an explicit probe ID was specified, discover * that specific probe and cache its description and arguments. */ if ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) != NULL) { size_t keylen = dt_probe_keylen(pdp); char *key = dt_probe_key(pdp, alloca(keylen)); if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL) prp = idp->di_data; else if (pdp->dtpd_id != DTRACE_IDNONE) prp = dt_probe_discover(pvp, pdp); + + if (strcmp(pvp->pv_desc.dtvd_name, "kinst") == 0) { + dtrace_kinst_probedesc_t pd; + + if (dtp->dt_kinstfd == -1) { + int fd; + + fd = open("/dev/dtrace/kinst", O_WRONLY); + if (fd < 0) { + (void) dt_set_errno(dtp, errno); + return (NULL); + } + dtp->dt_kinstfd = fd; + } + memset(&pd, 0, sizeof(pd)); + strlcpy(pd.kpd_func, pdp->dtpd_func, + sizeof (pd.kpd_func)); + + if (n_is_glob) + pd.kpd_off = -1; + else + pd.kpd_off = strtol(pdp->dtpd_name, NULL, 10); + if (ioctl(dtp->dt_kinstfd, KINSTIOC_MAKEPROBE, &pd) != + 0) { + (void) dt_set_errno(dtp, errno); + return (NULL); + } + } } /* * If no probe was found in our cache, convert the caller's partial * probe description into a fully-formed matching probe description by * iterating over up to at most two probes that match 'pdp'. We then * call dt_probe_discover() on the resulting probe identifier. */ if (prp == NULL) { dtrace_probedesc_t pd; int m; bzero(&pd, sizeof (pd)); pd.dtpd_id = DTRACE_IDNONE; /* * Call dtrace_probe_iter() to find matching probes. Our * dt_probe_desc() callback will produce the following results: * * m < 0 dtrace_probe_iter() found zero matches (or failed). * m > 0 dtrace_probe_iter() found more than one match. * m = 0 dtrace_probe_iter() found exactly one match. */ if ((m = dtrace_probe_iter(dtp, pdp, dt_probe_desc, &pd)) < 0) return (NULL); /* dt_errno is set for us */ if ((pvp = dt_provider_lookup(dtp, pd.dtpd_provider)) == NULL) return (NULL); /* dt_errno is set for us */ /* * If more than one probe was matched, then do not report probe * information if either of the following conditions is true: * * (a) The Arguments Data stability of the matched provider is * less than Evolving. * * (b) Any description component that is at least Evolving is * empty or is specified using a globbing expression. * * These conditions imply that providers that provide Evolving * or better Arguments Data stability must guarantee that all * probes with identical field names in a field of Evolving or * better Name stability have identical argument signatures. */ if (m > 0) { if (pvp->pv_desc.dtvd_attr.dtpa_args.dtat_data < DTRACE_STABILITY_EVOLVING) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } if (pvp->pv_desc.dtvd_attr.dtpa_mod.dtat_name >= DTRACE_STABILITY_EVOLVING && m_is_glob) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } if (pvp->pv_desc.dtvd_attr.dtpa_func.dtat_name >= DTRACE_STABILITY_EVOLVING && f_is_glob) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } if (pvp->pv_desc.dtvd_attr.dtpa_name.dtat_name >= DTRACE_STABILITY_EVOLVING && n_is_glob) { (void) dt_set_errno(dtp, EDT_UNSTABLE); return (NULL); } } /* * If we matched a probe exported by dtrace(7D), then discover * the real attributes. Otherwise grab the static declaration. */ if (pd.dtpd_id != DTRACE_IDNONE) prp = dt_probe_discover(pvp, &pd); else prp = dt_probe_lookup(pvp, pd.dtpd_name); if (prp == NULL) return (NULL); /* dt_errno is set for us */ } assert(pvp != NULL && prp != NULL); /* * Compute the probe description attributes by taking the minimum of * the attributes of the specified fields. If no provider is specified * or a glob pattern is used for the provider, use Unstable attributes. */ if (pdp->dtpd_provider[0] == '\0' || strisglob(pdp->dtpd_provider)) pap = &_dtrace_prvdesc; else pap = &pvp->pv_desc.dtvd_attr; pip->dtp_attr = pap->dtpa_provider; if (!m_is_glob) pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_mod); if (!f_is_glob) pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_func); if (!n_is_glob) pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_name); pip->dtp_arga = pap->dtpa_args; pip->dtp_argv = prp->pr_argv; pip->dtp_argc = prp->pr_argc; return (prp); } int dtrace_probe_info(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip) { return (dt_probe_info(dtp, pdp, pip) != NULL ? 0 : -1); } /*ARGSUSED*/ static int dt_probe_iter(dt_idhash_t *ihp, dt_ident_t *idp, dt_probe_iter_t *pit) { const dt_probe_t *prp = idp->di_data; if (!dt_gmatch(prp->pr_name, pit->pit_pat)) return (0); /* continue on and examine next probe in hash */ (void) strlcpy(pit->pit_desc.dtpd_name, prp->pr_name, DTRACE_NAMELEN); pit->pit_desc.dtpd_id = idp->di_id; pit->pit_matches++; return (pit->pit_func(pit->pit_hdl, &pit->pit_desc, pit->pit_arg)); } int dtrace_probe_iter(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, dtrace_probe_f *func, void *arg) { const char *provider = pdp ? pdp->dtpd_provider : NULL; dtrace_id_t id = DTRACE_IDNONE; dtrace_probedesc_t pd; dt_probe_iter_t pit; int cmd, rv; bzero(&pit, sizeof (pit)); pit.pit_hdl = dtp; pit.pit_func = func; pit.pit_arg = arg; pit.pit_pat = pdp ? pdp->dtpd_name : NULL; for (pit.pit_pvp = dt_list_next(&dtp->dt_provlist); pit.pit_pvp != NULL; pit.pit_pvp = dt_list_next(pit.pit_pvp)) { if (pit.pit_pvp->pv_flags & DT_PROVIDER_IMPL) continue; /* we'll get these later using dt_ioctl() */ if (!dt_gmatch(pit.pit_pvp->pv_desc.dtvd_name, provider)) continue; (void) strlcpy(pit.pit_desc.dtpd_provider, pit.pit_pvp->pv_desc.dtvd_name, DTRACE_PROVNAMELEN); if ((rv = dt_idhash_iter(pit.pit_pvp->pv_probes, (dt_idhash_f *)dt_probe_iter, &pit)) != 0) return (rv); } if (pdp != NULL) cmd = DTRACEIOC_PROBEMATCH; else cmd = DTRACEIOC_PROBES; for (;;) { if (pdp != NULL) bcopy(pdp, &pd, sizeof (pd)); pd.dtpd_id = id; if (dt_ioctl(dtp, cmd, &pd) != 0) break; else if ((rv = func(dtp, &pd, arg)) != 0) return (rv); pit.pit_matches++; id = pd.dtpd_id + 1; } switch (errno) { case ESRCH: case EBADF: return (pit.pit_matches ? 0 : dt_set_errno(dtp, EDT_NOPROBE)); case EINVAL: return (dt_set_errno(dtp, EDT_BADPGLOB)); default: return (dt_set_errno(dtp, errno)); } } diff --git a/cddl/lib/libdtrace/Makefile b/cddl/lib/libdtrace/Makefile index f95517f10ebb..651609409a3a 100644 --- a/cddl/lib/libdtrace/Makefile +++ b/cddl/lib/libdtrace/Makefile @@ -1,140 +1,141 @@ # $FreeBSD$ .PATH: ${SRCTOP}/cddl/contrib/opensolaris/lib/libdtrace/common .PATH: ${SRCTOP}/cddl/contrib/opensolaris/lib/libgen/common PACKAGE= dtrace LIB= dtrace SRCS= dt_aggregate.c \ dt_as.c \ dt_buf.c \ dt_cc.c \ dt_cg.c \ dt_consume.c \ dt_decl.c \ dt_dis.c \ dt_dof.c \ dt_error.c \ dt_errtags.c \ dt_grammar.y \ dt_handle.c \ dt_ident.c \ dt_isadep.c \ dt_inttab.c \ dt_lex.l \ dt_link.c \ dt_list.c \ dt_map.c \ dt_module.c \ dt_names.c \ dt_open.c \ dt_options.c \ dt_parser.c \ dt_pcb.c \ dt_pid.c \ dt_pq.c \ dt_pragma.c \ dt_print.c \ dt_printf.c \ dt_proc.c \ dt_program.c \ dt_provider.c \ dt_regset.c \ dt_string.c \ dt_strtab.c \ dt_subr.c \ dt_sugar.c \ dt_work.c \ dt_xlator.c \ gmatch.c DSRCS= errno.d \ io.d \ ip.d \ psinfo.d \ sctp.d \ siftr.d \ signal.d \ tcp.d \ socket.d \ udp.d \ udplite.d \ unistd.d FILES= ${DSRCS} FILESDIR= /usr/lib/dtrace FILESMODE= ${NOBINMODE} INCSGROUPS= INCS SYSINCS SYSINCSDIR= ${INCLUDEDIR}/sys INCS+= ${SRCTOP}/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h SYSINCS+= ${SRCTOP}/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h SYSINCS+= ${SRCTOP}/sys/cddl/contrib/opensolaris/uts/common/sys/ctf_api.h WARNS?= 1 CFLAGS+= -DIN_BASE CFLAGS+= -I${SRCTOP}/sys/contrib/openzfs/include CFLAGS+= -I${SRCTOP}/sys/contrib/openzfs/lib/libspl/include/ CFLAGS+= -I${SRCTOP}/sys/contrib/openzfs/lib/libspl/include/os/freebsd CFLAGS+= -I${SRCTOP}/sys CFLAGS+= -include ${SRCTOP}/sys/contrib/openzfs/include/os/freebsd/spl/sys/ccompile.h CFLAGS+= -DHAVE_ISSETUGID CFLAGS+= -I${.OBJDIR} -I${.CURDIR} \ -I${SRCTOP}/sys/cddl/dev/dtrace/${MACHINE_ARCH} \ + -I${SRCTOP}/sys/cddl/dev/kinst \ -I${SRCTOP}/sys/cddl/compat/opensolaris \ -I${SRCTOP}/cddl/compat/opensolaris/include \ -I${OPENSOLARIS_USR_DISTDIR}/head \ -I${OPENSOLARIS_USR_DISTDIR}/lib/libctf/common \ -I${OPENSOLARIS_USR_DISTDIR}/lib/libdtrace/common \ -I${OPENSOLARIS_SYS_DISTDIR}/uts/common #CFLAGS+= -DYYDEBUG .if ${MACHINE_CPUARCH} == "aarch64" CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/aarch64 .PATH: ${SRCTOP}/cddl/contrib/opensolaris/lib/libdtrace/aarch64 .PATH: ${SRCTOP}/sys/cddl/dev/dtrace/aarch64 .elif ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" CFLAGS+= -I${SRCTOP}/sys/cddl/dev/dtrace/x86 CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel -DDIS_MEM .PATH: ${SRCTOP}/cddl/contrib/opensolaris/lib/libdtrace/i386 .PATH: ${SRCTOP}/sys/cddl/dev/dtrace/${MACHINE_ARCH} .PATH: ${SRCTOP}/sys/cddl/dev/dtrace/x86 .elif ${MACHINE_CPUARCH} == "arm" CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/arm .PATH: ${SRCTOP}/cddl/contrib/opensolaris/lib/libdtrace/arm .PATH: ${SRCTOP}/sys/cddl/dev/dtrace/arm .elif ${MACHINE_CPUARCH} == "powerpc" CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/powerpc .PATH: ${SRCTOP}/cddl/contrib/opensolaris/lib/libdtrace/powerpc .PATH: ${SRCTOP}/sys/cddl/dev/dtrace/powerpc .elif ${MACHINE_CPUARCH} == "riscv" CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/riscv .PATH: ${SRCTOP}/cddl/contrib/opensolaris/lib/libdtrace/riscv .PATH: ${SRCTOP}/sys/cddl/dev/dtrace/riscv .else # temporary hack CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel .endif .if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" SRCS+= dis_tables.c DSRCS+= regs_x86.d .endif YFLAGS+=-d LIBADD= ctf elf proc pthread rtld_db CLEANFILES= dt_errtags.c dt_names.c .include dt_errtags.c: ${OPENSOLARIS_USR_DISTDIR}/lib/libdtrace/common/dt_errtags.h sh ${OPENSOLARIS_USR_DISTDIR}/lib/libdtrace/common/mkerrtags.sh < ${.ALLSRC} > ${.TARGET} dt_names.c: ${OPENSOLARIS_SYS_DISTDIR}/uts/common/sys/dtrace.h sh ${OPENSOLARIS_USR_DISTDIR}/lib/libdtrace/common/mknames.sh < ${.ALLSRC} > ${.TARGET}