diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h index 6bcc5bc49ab0..a712d24955c6 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h @@ -1,691 +1,692 @@ /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _DT_IMPL_H #define _DT_IMPL_H #pragma ident "%Z%%M% %I% %E% SMI" #include #include #if !defined(sun) #include #include #include #include #include #endif #include #include #include #include #ifdef __cplusplus extern "C" { #endif #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 */ #if !defined(sun) caddr_t dm_reloc_offset; /* Symbol relocation offset. */ + uintptr_t *dm_sec_offsets; #endif } 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 */ 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 */ } 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 */ 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 */ 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 */ dt_aggregate_t dt_aggregate; /* aggregate */ dtrace_bufdesc_t dt_buf; /* staging buffer */ 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 */ 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_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 */ #if !defined(sun) 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_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 */ #if defined(sun) 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 */ }; /* * 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 */ /* * 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_PRINTM DT_ACT(29) /* printm() action */ #define DT_ACT_PRINTT DT_ACT(30) /* printt() 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_NOREG, /* register allocation failure */ 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 */ }; /* * 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 *); #if defined(sun) 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); #if defined(sun) 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 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 uint64_t dt_stddev(uint64_t *, uint64_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 int dt_options_load(dtrace_hdl_t *); 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 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_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 __cplusplus } #endif #endif /* _DT_IMPL_H */ diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c index af175012b3be..d33fb95e499d 100644 --- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c +++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_module.c @@ -1,1383 +1,1446 @@ /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #if defined(sun) #include #include #include #include #include #include #else #include #include #include #endif #include #if defined(sun) #include #endif #include #include #include #include #include #include #include #if !defined(sun) #include #endif #include #include #include static const char *dt_module_strtab; /* active strtab for qsort callbacks */ static void dt_module_symhash_insert(dt_module_t *dmp, const char *name, uint_t id) { dt_sym_t *dsp = &dmp->dm_symchains[dmp->dm_symfree]; uint_t h; assert(dmp->dm_symfree < dmp->dm_nsymelems + 1); dsp->ds_symid = id; h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; dsp->ds_next = dmp->dm_symbuckets[h]; dmp->dm_symbuckets[h] = dmp->dm_symfree++; } static uint_t dt_module_syminit32(dt_module_t *dmp) { Elf32_Sym *sym = dmp->dm_symtab.cts_data; const char *base = dmp->dm_strtab.cts_data; size_t ss_size = dmp->dm_strtab.cts_size; uint_t i, n = dmp->dm_nsymelems; uint_t asrsv = 0; +#if defined(__FreeBSD__) + GElf_Ehdr ehdr; + int is_elf_obj; + + gelf_getehdr(dmp->dm_elf, &ehdr); + is_elf_obj = (ehdr.e_type == ET_REL); +#endif + for (i = 0; i < n; i++, sym++) { const char *name = base + sym->st_name; uchar_t type = ELF32_ST_TYPE(sym->st_info); if (type >= STT_NUM || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name == 0 || sym->st_name >= ss_size) continue; /* skip null or invalid names */ if (sym->st_value != 0 && (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) { asrsv++; /* reserve space in the address map */ -#if !defined(sun) +#if defined(__FreeBSD__) sym->st_value += (Elf_Addr) dmp->dm_reloc_offset; + if (is_elf_obj && sym->st_shndx != SHN_UNDEF && + sym->st_shndx < ehdr.e_shnum) + sym->st_value += + dmp->dm_sec_offsets[sym->st_shndx]; #endif } dt_module_symhash_insert(dmp, name, i); } return (asrsv); } static uint_t dt_module_syminit64(dt_module_t *dmp) { Elf64_Sym *sym = dmp->dm_symtab.cts_data; const char *base = dmp->dm_strtab.cts_data; size_t ss_size = dmp->dm_strtab.cts_size; uint_t i, n = dmp->dm_nsymelems; uint_t asrsv = 0; +#if defined(__FreeBSD__) + GElf_Ehdr ehdr; + int is_elf_obj; + + gelf_getehdr(dmp->dm_elf, &ehdr); + is_elf_obj = (ehdr.e_type == ET_REL); +#endif + for (i = 0; i < n; i++, sym++) { const char *name = base + sym->st_name; uchar_t type = ELF64_ST_TYPE(sym->st_info); if (type >= STT_NUM || type == STT_SECTION) continue; /* skip sections and unknown types */ if (sym->st_name == 0 || sym->st_name >= ss_size) continue; /* skip null or invalid names */ if (sym->st_value != 0 && (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) { asrsv++; /* reserve space in the address map */ - -#if !defined(sun) +#if defined(__FreeBSD__) sym->st_value += (Elf_Addr) dmp->dm_reloc_offset; + if (is_elf_obj && sym->st_shndx != SHN_UNDEF && + sym->st_shndx < ehdr.e_shnum) + sym->st_value += + dmp->dm_sec_offsets[sym->st_shndx]; #endif } dt_module_symhash_insert(dmp, name, i); } return (asrsv); } /* * Sort comparison function for 32-bit symbol address-to-name lookups. We sort * symbols by value. If values are equal, we prefer the symbol that is * non-zero sized, typed, not weak, or lexically first, in that order. */ static int dt_module_symcomp32(const void *lp, const void *rp) { Elf32_Sym *lhs = *((Elf32_Sym **)lp); Elf32_Sym *rhs = *((Elf32_Sym **)rp); if (lhs->st_value != rhs->st_value) return (lhs->st_value > rhs->st_value ? 1 : -1); if ((lhs->st_size == 0) != (rhs->st_size == 0)) return (lhs->st_size == 0 ? 1 : -1); if ((ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE) != (ELF32_ST_TYPE(rhs->st_info) == STT_NOTYPE)) return (ELF32_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); if ((ELF32_ST_BIND(lhs->st_info) == STB_WEAK) != (ELF32_ST_BIND(rhs->st_info) == STB_WEAK)) return (ELF32_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); return (strcmp(dt_module_strtab + lhs->st_name, dt_module_strtab + rhs->st_name)); } /* * Sort comparison function for 64-bit symbol address-to-name lookups. We sort * symbols by value. If values are equal, we prefer the symbol that is * non-zero sized, typed, not weak, or lexically first, in that order. */ static int dt_module_symcomp64(const void *lp, const void *rp) { Elf64_Sym *lhs = *((Elf64_Sym **)lp); Elf64_Sym *rhs = *((Elf64_Sym **)rp); if (lhs->st_value != rhs->st_value) return (lhs->st_value > rhs->st_value ? 1 : -1); if ((lhs->st_size == 0) != (rhs->st_size == 0)) return (lhs->st_size == 0 ? 1 : -1); if ((ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE) != (ELF64_ST_TYPE(rhs->st_info) == STT_NOTYPE)) return (ELF64_ST_TYPE(lhs->st_info) == STT_NOTYPE ? 1 : -1); if ((ELF64_ST_BIND(lhs->st_info) == STB_WEAK) != (ELF64_ST_BIND(rhs->st_info) == STB_WEAK)) return (ELF64_ST_BIND(lhs->st_info) == STB_WEAK ? 1 : -1); return (strcmp(dt_module_strtab + lhs->st_name, dt_module_strtab + rhs->st_name)); } static void dt_module_symsort32(dt_module_t *dmp) { Elf32_Sym *symtab = (Elf32_Sym *)dmp->dm_symtab.cts_data; Elf32_Sym **sympp = (Elf32_Sym **)dmp->dm_asmap; const dt_sym_t *dsp = dmp->dm_symchains + 1; uint_t i, n = dmp->dm_symfree; for (i = 1; i < n; i++, dsp++) { Elf32_Sym *sym = symtab + dsp->ds_symid; if (sym->st_value != 0 && (ELF32_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) *sympp++ = sym; } dmp->dm_aslen = (uint_t)(sympp - (Elf32_Sym **)dmp->dm_asmap); assert(dmp->dm_aslen <= dmp->dm_asrsv); dt_module_strtab = dmp->dm_strtab.cts_data; qsort(dmp->dm_asmap, dmp->dm_aslen, sizeof (Elf32_Sym *), dt_module_symcomp32); dt_module_strtab = NULL; } static void dt_module_symsort64(dt_module_t *dmp) { Elf64_Sym *symtab = (Elf64_Sym *)dmp->dm_symtab.cts_data; Elf64_Sym **sympp = (Elf64_Sym **)dmp->dm_asmap; const dt_sym_t *dsp = dmp->dm_symchains + 1; uint_t i, n = dmp->dm_symfree; for (i = 1; i < n; i++, dsp++) { Elf64_Sym *sym = symtab + dsp->ds_symid; if (sym->st_value != 0 && (ELF64_ST_BIND(sym->st_info) != STB_LOCAL || sym->st_size)) *sympp++ = sym; } dmp->dm_aslen = (uint_t)(sympp - (Elf64_Sym **)dmp->dm_asmap); assert(dmp->dm_aslen <= dmp->dm_asrsv); dt_module_strtab = dmp->dm_strtab.cts_data; qsort(dmp->dm_asmap, dmp->dm_aslen, sizeof (Elf64_Sym *), dt_module_symcomp64); dt_module_strtab = NULL; } static GElf_Sym * dt_module_symgelf32(const Elf32_Sym *src, GElf_Sym *dst) { if (dst != NULL) { dst->st_name = src->st_name; dst->st_info = src->st_info; dst->st_other = src->st_other; dst->st_shndx = src->st_shndx; dst->st_value = src->st_value; dst->st_size = src->st_size; } return (dst); } static GElf_Sym * dt_module_symgelf64(const Elf64_Sym *src, GElf_Sym *dst) { if (dst != NULL) bcopy(src, dst, sizeof (GElf_Sym)); return (dst); } static GElf_Sym * dt_module_symname32(dt_module_t *dmp, const char *name, GElf_Sym *symp, uint_t *idp) { const Elf32_Sym *symtab = dmp->dm_symtab.cts_data; const char *strtab = dmp->dm_strtab.cts_data; const Elf32_Sym *sym; const dt_sym_t *dsp; uint_t i, h; if (dmp->dm_nsymelems == 0) return (NULL); h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) { dsp = &dmp->dm_symchains[i]; sym = symtab + dsp->ds_symid; if (strcmp(name, strtab + sym->st_name) == 0) { if (idp != NULL) *idp = dsp->ds_symid; return (dt_module_symgelf32(sym, symp)); } } return (NULL); } static GElf_Sym * dt_module_symname64(dt_module_t *dmp, const char *name, GElf_Sym *symp, uint_t *idp) { const Elf64_Sym *symtab = dmp->dm_symtab.cts_data; const char *strtab = dmp->dm_strtab.cts_data; const Elf64_Sym *sym; const dt_sym_t *dsp; uint_t i, h; if (dmp->dm_nsymelems == 0) return (NULL); h = dt_strtab_hash(name, NULL) % dmp->dm_nsymbuckets; for (i = dmp->dm_symbuckets[h]; i != 0; i = dsp->ds_next) { dsp = &dmp->dm_symchains[i]; sym = symtab + dsp->ds_symid; if (strcmp(name, strtab + sym->st_name) == 0) { if (idp != NULL) *idp = dsp->ds_symid; return (dt_module_symgelf64(sym, symp)); } } return (NULL); } static GElf_Sym * dt_module_symaddr32(dt_module_t *dmp, GElf_Addr addr, GElf_Sym *symp, uint_t *idp) { const Elf32_Sym **asmap = (const Elf32_Sym **)dmp->dm_asmap; const Elf32_Sym *symtab = dmp->dm_symtab.cts_data; const Elf32_Sym *sym; uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1; Elf32_Addr v; if (dmp->dm_aslen == 0) return (NULL); while (hi - lo > 1) { mid = (lo + hi) / 2; if (addr >= asmap[mid]->st_value) lo = mid; else hi = mid; } i = addr < asmap[hi]->st_value ? lo : hi; sym = asmap[i]; v = sym->st_value; /* * If the previous entry has the same value, improve our choice. The * order of equal-valued symbols is determined by the comparison func. */ while (i-- != 0 && asmap[i]->st_value == v) sym = asmap[i]; if (addr - sym->st_value < MAX(sym->st_size, 1)) { if (idp != NULL) *idp = (uint_t)(sym - symtab); return (dt_module_symgelf32(sym, symp)); } return (NULL); } static GElf_Sym * dt_module_symaddr64(dt_module_t *dmp, GElf_Addr addr, GElf_Sym *symp, uint_t *idp) { const Elf64_Sym **asmap = (const Elf64_Sym **)dmp->dm_asmap; const Elf64_Sym *symtab = dmp->dm_symtab.cts_data; const Elf64_Sym *sym; uint_t i, mid, lo = 0, hi = dmp->dm_aslen - 1; Elf64_Addr v; if (dmp->dm_aslen == 0) return (NULL); while (hi - lo > 1) { mid = (lo + hi) / 2; if (addr >= asmap[mid]->st_value) lo = mid; else hi = mid; } i = addr < asmap[hi]->st_value ? lo : hi; sym = asmap[i]; v = sym->st_value; /* * If the previous entry has the same value, improve our choice. The * order of equal-valued symbols is determined by the comparison func. */ while (i-- != 0 && asmap[i]->st_value == v) sym = asmap[i]; if (addr - sym->st_value < MAX(sym->st_size, 1)) { if (idp != NULL) *idp = (uint_t)(sym - symtab); return (dt_module_symgelf64(sym, symp)); } return (NULL); } static const dt_modops_t dt_modops_32 = { dt_module_syminit32, dt_module_symsort32, dt_module_symname32, dt_module_symaddr32 }; static const dt_modops_t dt_modops_64 = { dt_module_syminit64, dt_module_symsort64, dt_module_symname64, dt_module_symaddr64 }; dt_module_t * dt_module_create(dtrace_hdl_t *dtp, const char *name) { uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; dt_module_t *dmp; for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { if (strcmp(dmp->dm_name, name) == 0) return (dmp); } if ((dmp = malloc(sizeof (dt_module_t))) == NULL) return (NULL); /* caller must handle allocation failure */ bzero(dmp, sizeof (dt_module_t)); (void) strlcpy(dmp->dm_name, name, sizeof (dmp->dm_name)); dt_list_append(&dtp->dt_modlist, dmp); dmp->dm_next = dtp->dt_mods[h]; dtp->dt_mods[h] = dmp; dtp->dt_nmods++; if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64) dmp->dm_ops = &dt_modops_64; else dmp->dm_ops = &dt_modops_32; return (dmp); } dt_module_t * dt_module_lookup_by_name(dtrace_hdl_t *dtp, const char *name) { uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_modbuckets; dt_module_t *dmp; for (dmp = dtp->dt_mods[h]; dmp != NULL; dmp = dmp->dm_next) { if (strcmp(dmp->dm_name, name) == 0) return (dmp); } return (NULL); } /*ARGSUSED*/ dt_module_t * dt_module_lookup_by_ctf(dtrace_hdl_t *dtp, ctf_file_t *ctfp) { return (ctfp ? ctf_getspecific(ctfp) : NULL); } static int dt_module_load_sect(dtrace_hdl_t *dtp, dt_module_t *dmp, ctf_sect_t *ctsp) { const char *s; size_t shstrs; GElf_Shdr sh; Elf_Data *dp; Elf_Scn *sp; if (elf_getshstrndx(dmp->dm_elf, &shstrs) == 0) return (dt_set_errno(dtp, EDT_NOTLOADED)); for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) { if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL || (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL) continue; /* skip any malformed sections */ if (sh.sh_type == ctsp->cts_type && sh.sh_entsize == ctsp->cts_entsize && strcmp(s, ctsp->cts_name) == 0) break; /* section matches specification */ } /* * If the section isn't found, return success but leave cts_data set * to NULL and cts_size set to zero for our caller. */ if (sp == NULL || (dp = elf_getdata(sp, NULL)) == NULL) return (0); #if defined(sun) ctsp->cts_data = dp->d_buf; #else if ((ctsp->cts_data = malloc(dp->d_size)) == NULL) return (0); memcpy(ctsp->cts_data, dp->d_buf, dp->d_size); #endif ctsp->cts_size = dp->d_size; dt_dprintf("loaded %s [%s] (%lu bytes)\n", dmp->dm_name, ctsp->cts_name, (ulong_t)ctsp->cts_size); return (0); } int dt_module_load(dtrace_hdl_t *dtp, dt_module_t *dmp) { if (dmp->dm_flags & DT_DM_LOADED) return (0); /* module is already loaded */ dmp->dm_ctdata.cts_name = ".SUNW_ctf"; dmp->dm_ctdata.cts_type = SHT_PROGBITS; dmp->dm_ctdata.cts_flags = 0; dmp->dm_ctdata.cts_data = NULL; dmp->dm_ctdata.cts_size = 0; dmp->dm_ctdata.cts_entsize = 0; dmp->dm_ctdata.cts_offset = 0; dmp->dm_symtab.cts_name = ".symtab"; dmp->dm_symtab.cts_type = SHT_SYMTAB; dmp->dm_symtab.cts_flags = 0; dmp->dm_symtab.cts_data = NULL; dmp->dm_symtab.cts_size = 0; dmp->dm_symtab.cts_entsize = dmp->dm_ops == &dt_modops_64 ? sizeof (Elf64_Sym) : sizeof (Elf32_Sym); dmp->dm_symtab.cts_offset = 0; dmp->dm_strtab.cts_name = ".strtab"; dmp->dm_strtab.cts_type = SHT_STRTAB; dmp->dm_strtab.cts_flags = 0; dmp->dm_strtab.cts_data = NULL; dmp->dm_strtab.cts_size = 0; dmp->dm_strtab.cts_entsize = 0; dmp->dm_strtab.cts_offset = 0; /* * Attempt to load the module's CTF section, symbol table section, and * string table section. Note that modules may not contain CTF data: * this will result in a successful load_sect but data of size zero. * We will then fail if dt_module_getctf() is called, as shown below. */ if (dt_module_load_sect(dtp, dmp, &dmp->dm_ctdata) == -1 || dt_module_load_sect(dtp, dmp, &dmp->dm_symtab) == -1 || dt_module_load_sect(dtp, dmp, &dmp->dm_strtab) == -1) { dt_module_unload(dtp, dmp); return (-1); /* dt_errno is set for us */ } /* * Allocate the hash chains and hash buckets for symbol name lookup. * This is relatively simple since the symbol table is of fixed size * and is known in advance. We allocate one extra element since we * use element indices instead of pointers and zero is our sentinel. */ dmp->dm_nsymelems = dmp->dm_symtab.cts_size / dmp->dm_symtab.cts_entsize; dmp->dm_nsymbuckets = _dtrace_strbuckets; dmp->dm_symfree = 1; /* first free element is index 1 */ dmp->dm_symbuckets = malloc(sizeof (uint_t) * dmp->dm_nsymbuckets); dmp->dm_symchains = malloc(sizeof (dt_sym_t) * dmp->dm_nsymelems + 1); if (dmp->dm_symbuckets == NULL || dmp->dm_symchains == NULL) { dt_module_unload(dtp, dmp); return (dt_set_errno(dtp, EDT_NOMEM)); } bzero(dmp->dm_symbuckets, sizeof (uint_t) * dmp->dm_nsymbuckets); bzero(dmp->dm_symchains, sizeof (dt_sym_t) * dmp->dm_nsymelems + 1); /* * Iterate over the symbol table data buffer and insert each symbol * name into the name hash if the name and type are valid. Then * allocate the address map, fill it in, and sort it. */ dmp->dm_asrsv = dmp->dm_ops->do_syminit(dmp); dt_dprintf("hashed %s [%s] (%u symbols)\n", dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_symfree - 1); if ((dmp->dm_asmap = malloc(sizeof (void *) * dmp->dm_asrsv)) == NULL) { dt_module_unload(dtp, dmp); return (dt_set_errno(dtp, EDT_NOMEM)); } dmp->dm_ops->do_symsort(dmp); dt_dprintf("sorted %s [%s] (%u symbols)\n", dmp->dm_name, dmp->dm_symtab.cts_name, dmp->dm_aslen); dmp->dm_flags |= DT_DM_LOADED; return (0); } ctf_file_t * dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp) { const char *parent; dt_module_t *pmp; ctf_file_t *pfp; int model; if (dmp->dm_ctfp != NULL || dt_module_load(dtp, dmp) != 0) return (dmp->dm_ctfp); if (dmp->dm_ops == &dt_modops_64) model = CTF_MODEL_LP64; else model = CTF_MODEL_ILP32; /* * If the data model of the module does not match our program data * model, then do not permit CTF from this module to be opened and * returned to the compiler. If we support mixed data models in the * future for combined kernel/user tracing, this can be removed. */ if (dtp->dt_conf.dtc_ctfmodel != model) { (void) dt_set_errno(dtp, EDT_DATAMODEL); return (NULL); } if (dmp->dm_ctdata.cts_size == 0) { (void) dt_set_errno(dtp, EDT_NOCTF); return (NULL); } dmp->dm_ctfp = ctf_bufopen(&dmp->dm_ctdata, &dmp->dm_symtab, &dmp->dm_strtab, &dtp->dt_ctferr); if (dmp->dm_ctfp == NULL) { (void) dt_set_errno(dtp, EDT_CTF); return (NULL); } (void) ctf_setmodel(dmp->dm_ctfp, model); ctf_setspecific(dmp->dm_ctfp, dmp); if ((parent = ctf_parent_name(dmp->dm_ctfp)) != NULL) { if ((pmp = dt_module_create(dtp, parent)) == NULL || (pfp = dt_module_getctf(dtp, pmp)) == NULL) { if (pmp == NULL) (void) dt_set_errno(dtp, EDT_NOMEM); goto err; } if (ctf_import(dmp->dm_ctfp, pfp) == CTF_ERR) { dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp); (void) dt_set_errno(dtp, EDT_CTF); goto err; } } dt_dprintf("loaded CTF container for %s (%p)\n", dmp->dm_name, (void *)dmp->dm_ctfp); return (dmp->dm_ctfp); err: ctf_close(dmp->dm_ctfp); dmp->dm_ctfp = NULL; return (NULL); } /*ARGSUSED*/ void dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp) { ctf_close(dmp->dm_ctfp); dmp->dm_ctfp = NULL; #if !defined(sun) if (dmp->dm_ctdata.cts_data != NULL) { free(dmp->dm_ctdata.cts_data); } if (dmp->dm_symtab.cts_data != NULL) { free(dmp->dm_symtab.cts_data); } if (dmp->dm_strtab.cts_data != NULL) { free(dmp->dm_strtab.cts_data); } #endif bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t)); bzero(&dmp->dm_symtab, sizeof (ctf_sect_t)); bzero(&dmp->dm_strtab, sizeof (ctf_sect_t)); if (dmp->dm_symbuckets != NULL) { free(dmp->dm_symbuckets); dmp->dm_symbuckets = NULL; } if (dmp->dm_symchains != NULL) { free(dmp->dm_symchains); dmp->dm_symchains = NULL; } if (dmp->dm_asmap != NULL) { free(dmp->dm_asmap); dmp->dm_asmap = NULL; } - +#if defined(__FreeBSD__) + if (dmp->dm_sec_offsets != NULL) { + free(dmp->dm_sec_offsets); + dmp->dm_sec_offsets = NULL; + } +#endif dmp->dm_symfree = 0; dmp->dm_nsymbuckets = 0; dmp->dm_nsymelems = 0; dmp->dm_asrsv = 0; dmp->dm_aslen = 0; dmp->dm_text_va = 0; dmp->dm_text_size = 0; dmp->dm_data_va = 0; dmp->dm_data_size = 0; dmp->dm_bss_va = 0; dmp->dm_bss_size = 0; if (dmp->dm_extern != NULL) { dt_idhash_destroy(dmp->dm_extern); dmp->dm_extern = NULL; } (void) elf_end(dmp->dm_elf); dmp->dm_elf = NULL; dmp->dm_flags &= ~DT_DM_LOADED; } void dt_module_destroy(dtrace_hdl_t *dtp, dt_module_t *dmp) { dt_list_delete(&dtp->dt_modlist, dmp); assert(dtp->dt_nmods != 0); dtp->dt_nmods--; dt_module_unload(dtp, dmp); free(dmp); } /* * Insert a new external symbol reference into the specified module. The new * symbol will be marked as undefined and is assigned a symbol index beyond * any existing cached symbols from this module. We use the ident's di_data * field to store a pointer to a copy of the dtrace_syminfo_t for this symbol. */ dt_ident_t * dt_module_extern(dtrace_hdl_t *dtp, dt_module_t *dmp, const char *name, const dtrace_typeinfo_t *tip) { dtrace_syminfo_t *sip; dt_ident_t *idp; uint_t id; if (dmp->dm_extern == NULL && (dmp->dm_extern = dt_idhash_create( "extern", NULL, dmp->dm_nsymelems, UINT_MAX)) == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } if (dt_idhash_nextid(dmp->dm_extern, &id) == -1) { (void) dt_set_errno(dtp, EDT_SYMOFLOW); return (NULL); } if ((sip = malloc(sizeof (dtrace_syminfo_t))) == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); return (NULL); } idp = dt_idhash_insert(dmp->dm_extern, name, DT_IDENT_SYMBOL, 0, id, _dtrace_symattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen); if (idp == NULL) { (void) dt_set_errno(dtp, EDT_NOMEM); free(sip); return (NULL); } sip->dts_object = dmp->dm_name; sip->dts_name = idp->di_name; sip->dts_id = idp->di_id; idp->di_data = sip; idp->di_ctfp = tip->dtt_ctfp; idp->di_type = tip->dtt_type; return (idp); } const char * dt_module_modelname(dt_module_t *dmp) { if (dmp->dm_ops == &dt_modops_64) return ("64-bit"); else return ("32-bit"); } /* * Update our module cache by adding an entry for the specified module 'name'. * We create the dt_module_t and populate it using /system/object//. * * On FreeBSD, the module name is passed as the full module file name, * including the path. */ static void #if defined(sun) dt_module_update(dtrace_hdl_t *dtp, const char *name) #else dt_module_update(dtrace_hdl_t *dtp, struct kld_file_stat *k_stat) #endif { char fname[MAXPATHLEN]; struct stat64 st; int fd, err, bits; dt_module_t *dmp; const char *s; size_t shstrs; GElf_Shdr sh; Elf_Data *dp; Elf_Scn *sp; #if defined(sun) (void) snprintf(fname, sizeof (fname), "%s/%s/object", OBJFS_ROOT, name); #else + GElf_Ehdr ehdr; GElf_Phdr ph; char name[MAXPATHLEN]; + uintptr_t mapbase, alignmask; int i = 0; + int is_elf_obj; (void) strlcpy(name, k_stat->name, sizeof(name)); (void) strlcpy(fname, k_stat->pathname, sizeof(fname)); #endif if ((fd = open(fname, O_RDONLY)) == -1 || fstat64(fd, &st) == -1 || (dmp = dt_module_create(dtp, name)) == NULL) { dt_dprintf("failed to open %s: %s\n", fname, strerror(errno)); (void) close(fd); return; } /* * Since the module can unload out from under us (and /system/object * will return ENOENT), tell libelf to cook the entire file now and * then close the underlying file descriptor immediately. If this * succeeds, we know that we can continue safely using dmp->dm_elf. */ dmp->dm_elf = elf_begin(fd, ELF_C_READ, NULL); err = elf_cntl(dmp->dm_elf, ELF_C_FDREAD); (void) close(fd); if (dmp->dm_elf == NULL || err == -1 || elf_getshstrndx(dmp->dm_elf, &shstrs) == 0) { dt_dprintf("failed to load %s: %s\n", fname, elf_errmsg(elf_errno())); dt_module_destroy(dtp, dmp); return; } switch (gelf_getclass(dmp->dm_elf)) { case ELFCLASS32: dmp->dm_ops = &dt_modops_32; bits = 32; break; case ELFCLASS64: dmp->dm_ops = &dt_modops_64; bits = 64; break; default: dt_dprintf("failed to load %s: unknown ELF class\n", fname); dt_module_destroy(dtp, dmp); return; } - +#if defined(__FreeBSD__) + mapbase = (uintptr_t)k_stat->address; + gelf_getehdr(dmp->dm_elf, &ehdr); + is_elf_obj = (ehdr.e_type == ET_REL); + if (is_elf_obj) { + dmp->dm_sec_offsets = + malloc(ehdr.e_shnum * sizeof(*dmp->dm_sec_offsets)); + if (dmp->dm_sec_offsets == NULL) { + dt_dprintf("failed to allocate memory\n"); + dt_module_destroy(dtp, dmp); + return; + } + } +#endif /* * Iterate over the section headers locating various sections of * interest and use their attributes to flesh out the dt_module_t. */ for (sp = NULL; (sp = elf_nextscn(dmp->dm_elf, sp)) != NULL; ) { if (gelf_getshdr(sp, &sh) == NULL || sh.sh_type == SHT_NULL || (s = elf_strptr(dmp->dm_elf, shstrs, sh.sh_name)) == NULL) continue; /* skip any malformed sections */ - +#if defined(__FreeBSD__) + if (sh.sh_size == 0) + continue; + if (is_elf_obj && (sh.sh_type == SHT_PROGBITS || + sh.sh_type == SHT_NOBITS)) { + alignmask = sh.sh_addralign - 1; + mapbase += alignmask; + mapbase &= ~alignmask; + sh.sh_addr = mapbase; + dmp->dm_sec_offsets[elf_ndxscn(sp)] = sh.sh_addr; + mapbase += sh.sh_size; + } +#endif if (strcmp(s, ".text") == 0) { dmp->dm_text_size = sh.sh_size; dmp->dm_text_va = sh.sh_addr; } else if (strcmp(s, ".data") == 0) { dmp->dm_data_size = sh.sh_size; dmp->dm_data_va = sh.sh_addr; } else if (strcmp(s, ".bss") == 0) { dmp->dm_bss_size = sh.sh_size; dmp->dm_bss_va = sh.sh_addr; } else if (strcmp(s, ".info") == 0 && (dp = elf_getdata(sp, NULL)) != NULL) { bcopy(dp->d_buf, &dmp->dm_info, MIN(sh.sh_size, sizeof (dmp->dm_info))); } else if (strcmp(s, ".filename") == 0 && (dp = elf_getdata(sp, NULL)) != NULL) { (void) strlcpy(dmp->dm_file, dp->d_buf, sizeof (dmp->dm_file)); } } dmp->dm_flags |= DT_DM_KERNEL; #if defined(sun) dmp->dm_modid = (int)OBJFS_MODID(st.st_ino); #else + /* + * Include .rodata and special sections into .text. + * This depends on default section layout produced by GNU ld + * for ELF objects and libraries: + * [Text][R/O data][R/W data][Dynamic][BSS][Non loadable] + */ + dmp->dm_text_size = dmp->dm_data_va - dmp->dm_text_va; #if defined(__i386__) /* * Find the first load section and figure out the relocation * offset for the symbols. The kernel module will not need * relocation, but the kernel linker modules will. */ for (i = 0; gelf_getphdr(dmp->dm_elf, i, &ph) != NULL; i++) { if (ph.p_type == PT_LOAD) { dmp->dm_reloc_offset = k_stat->address - ph.p_vaddr; break; } } #endif #endif if (dmp->dm_info.objfs_info_primary) dmp->dm_flags |= DT_DM_PRIMARY; dt_dprintf("opened %d-bit module %s (%s) [%d]\n", bits, dmp->dm_name, dmp->dm_file, dmp->dm_modid); } /* * Unload all the loaded modules and then refresh the module cache with the * latest list of loaded modules and their address ranges. */ void dtrace_update(dtrace_hdl_t *dtp) { dt_module_t *dmp; DIR *dirp; #if defined(__FreeBSD__) int fileid; #endif for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; dmp = dt_list_next(dmp)) dt_module_unload(dtp, dmp); #if defined(sun) /* * Open /system/object and attempt to create a libdtrace module for * each kernel module that is loaded on the current system. */ if (!(dtp->dt_oflags & DTRACE_O_NOSYS) && (dirp = opendir(OBJFS_ROOT)) != NULL) { struct dirent *dp; while ((dp = readdir(dirp)) != NULL) { if (dp->d_name[0] != '.') dt_module_update(dtp, dp->d_name); } (void) closedir(dirp); } #elif defined(__FreeBSD__) /* * Use FreeBSD's kernel loader interface to discover what kernel * modules are loaded and create a libdtrace module for each one. */ for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { struct kld_file_stat k_stat; k_stat.version = sizeof(k_stat); if (kldstat(fileid, &k_stat) == 0) dt_module_update(dtp, &k_stat); } #endif /* * Look up all the macro identifiers and set di_id to the latest value. * This code collaborates with dt_lex.l on the use of di_id. We will * need to implement something fancier if we need to support non-ints. */ dt_idhash_lookup(dtp->dt_macros, "egid")->di_id = getegid(); dt_idhash_lookup(dtp->dt_macros, "euid")->di_id = geteuid(); dt_idhash_lookup(dtp->dt_macros, "gid")->di_id = getgid(); dt_idhash_lookup(dtp->dt_macros, "pid")->di_id = getpid(); dt_idhash_lookup(dtp->dt_macros, "pgid")->di_id = getpgid(0); dt_idhash_lookup(dtp->dt_macros, "ppid")->di_id = getppid(); #if defined(sun) dt_idhash_lookup(dtp->dt_macros, "projid")->di_id = getprojid(); #endif dt_idhash_lookup(dtp->dt_macros, "sid")->di_id = getsid(0); #if defined(sun) dt_idhash_lookup(dtp->dt_macros, "taskid")->di_id = gettaskid(); #endif dt_idhash_lookup(dtp->dt_macros, "uid")->di_id = getuid(); /* * Cache the pointers to the modules representing the base executable * and the run-time linker in the dtrace client handle. Note that on * x86 krtld is folded into unix, so if we don't find it, use unix * instead. */ dtp->dt_exec = dt_module_lookup_by_name(dtp, "genunix"); dtp->dt_rtld = dt_module_lookup_by_name(dtp, "krtld"); if (dtp->dt_rtld == NULL) dtp->dt_rtld = dt_module_lookup_by_name(dtp, "unix"); /* * If this is the first time we are initializing the module list, * remove the module for genunix from the module list and then move it * to the front of the module list. We do this so that type and symbol * queries encounter genunix and thereby optimize for the common case * in dtrace_lookup_by_name() and dtrace_lookup_by_type(), below. */ if (dtp->dt_exec != NULL && dtp->dt_cdefs == NULL && dtp->dt_ddefs == NULL) { dt_list_delete(&dtp->dt_modlist, dtp->dt_exec); dt_list_prepend(&dtp->dt_modlist, dtp->dt_exec); } } static dt_module_t * dt_module_from_object(dtrace_hdl_t *dtp, const char *object) { int err = EDT_NOMOD; dt_module_t *dmp; switch ((uintptr_t)object) { case (uintptr_t)DTRACE_OBJ_EXEC: dmp = dtp->dt_exec; break; case (uintptr_t)DTRACE_OBJ_RTLD: dmp = dtp->dt_rtld; break; case (uintptr_t)DTRACE_OBJ_CDEFS: dmp = dtp->dt_cdefs; break; case (uintptr_t)DTRACE_OBJ_DDEFS: dmp = dtp->dt_ddefs; break; default: dmp = dt_module_create(dtp, object); err = EDT_NOMEM; } if (dmp == NULL) (void) dt_set_errno(dtp, err); return (dmp); } /* * Exported interface to look up a symbol by name. We return the GElf_Sym and * complete symbol information for the matching symbol. */ int dtrace_lookup_by_name(dtrace_hdl_t *dtp, const char *object, const char *name, GElf_Sym *symp, dtrace_syminfo_t *sip) { dt_module_t *dmp; dt_ident_t *idp; uint_t n, id; GElf_Sym sym; uint_t mask = 0; /* mask of dt_module flags to match */ uint_t bits = 0; /* flag bits that must be present */ if (object != DTRACE_OBJ_EVERY && object != DTRACE_OBJ_KMODS && object != DTRACE_OBJ_UMODS) { if ((dmp = dt_module_from_object(dtp, object)) == NULL) return (-1); /* dt_errno is set for us */ if (dt_module_load(dtp, dmp) == -1) return (-1); /* dt_errno is set for us */ n = 1; } else { if (object == DTRACE_OBJ_KMODS) mask = bits = DT_DM_KERNEL; else if (object == DTRACE_OBJ_UMODS) mask = DT_DM_KERNEL; dmp = dt_list_next(&dtp->dt_modlist); n = dtp->dt_nmods; } if (symp == NULL) symp = &sym; for (; n > 0; n--, dmp = dt_list_next(dmp)) { if ((dmp->dm_flags & mask) != bits) continue; /* failed to match required attributes */ if (dt_module_load(dtp, dmp) == -1) continue; /* failed to load symbol table */ if (dmp->dm_ops->do_symname(dmp, name, symp, &id) != NULL) { if (sip != NULL) { sip->dts_object = dmp->dm_name; sip->dts_name = (const char *) dmp->dm_strtab.cts_data + symp->st_name; sip->dts_id = id; } return (0); } if (dmp->dm_extern != NULL && (idp = dt_idhash_lookup(dmp->dm_extern, name)) != NULL) { if (symp != &sym) { symp->st_name = (uintptr_t)idp->di_name; symp->st_info = GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE); symp->st_other = 0; symp->st_shndx = SHN_UNDEF; symp->st_value = 0; symp->st_size = ctf_type_size(idp->di_ctfp, idp->di_type); } if (sip != NULL) { sip->dts_object = dmp->dm_name; sip->dts_name = idp->di_name; sip->dts_id = idp->di_id; } return (0); } } return (dt_set_errno(dtp, EDT_NOSYM)); } /* * Exported interface to look up a symbol by address. We return the GElf_Sym * and complete symbol information for the matching symbol. */ int dtrace_lookup_by_addr(dtrace_hdl_t *dtp, GElf_Addr addr, GElf_Sym *symp, dtrace_syminfo_t *sip) { dt_module_t *dmp; uint_t id; const dtrace_vector_t *v = dtp->dt_vector; if (v != NULL) return (v->dtv_lookup_by_addr(dtp->dt_varg, addr, symp, sip)); for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; dmp = dt_list_next(dmp)) { if (addr - dmp->dm_text_va < dmp->dm_text_size || addr - dmp->dm_data_va < dmp->dm_data_size || addr - dmp->dm_bss_va < dmp->dm_bss_size) break; } if (dmp == NULL) return (dt_set_errno(dtp, EDT_NOSYMADDR)); if (dt_module_load(dtp, dmp) == -1) return (-1); /* dt_errno is set for us */ if (symp != NULL) { if (dmp->dm_ops->do_symaddr(dmp, addr, symp, &id) == NULL) return (dt_set_errno(dtp, EDT_NOSYMADDR)); } if (sip != NULL) { sip->dts_object = dmp->dm_name; if (symp != NULL) { sip->dts_name = (const char *) dmp->dm_strtab.cts_data + symp->st_name; sip->dts_id = id; } else { sip->dts_name = NULL; sip->dts_id = 0; } } return (0); } int dtrace_lookup_by_type(dtrace_hdl_t *dtp, const char *object, const char *name, dtrace_typeinfo_t *tip) { dtrace_typeinfo_t ti; dt_module_t *dmp; int found = 0; ctf_id_t id; uint_t n; int justone; uint_t mask = 0; /* mask of dt_module flags to match */ uint_t bits = 0; /* flag bits that must be present */ if (object != DTRACE_OBJ_EVERY && object != DTRACE_OBJ_KMODS && object != DTRACE_OBJ_UMODS) { if ((dmp = dt_module_from_object(dtp, object)) == NULL) return (-1); /* dt_errno is set for us */ if (dt_module_load(dtp, dmp) == -1) return (-1); /* dt_errno is set for us */ n = 1; justone = 1; } else { if (object == DTRACE_OBJ_KMODS) mask = bits = DT_DM_KERNEL; else if (object == DTRACE_OBJ_UMODS) mask = DT_DM_KERNEL; dmp = dt_list_next(&dtp->dt_modlist); n = dtp->dt_nmods; justone = 0; } if (tip == NULL) tip = &ti; for (; n > 0; n--, dmp = dt_list_next(dmp)) { if ((dmp->dm_flags & mask) != bits) continue; /* failed to match required attributes */ /* * If we can't load the CTF container, continue on to the next * module. If our search was scoped to only one module then * return immediately leaving dt_errno unmodified. */ if (dt_module_getctf(dtp, dmp) == NULL) { if (justone) return (-1); continue; } /* * Look up the type in the module's CTF container. If our * match is a forward declaration tag, save this choice in * 'tip' and keep going in the hope that we will locate the * underlying structure definition. Otherwise just return. */ if ((id = ctf_lookup_by_name(dmp->dm_ctfp, name)) != CTF_ERR) { tip->dtt_object = dmp->dm_name; tip->dtt_ctfp = dmp->dm_ctfp; tip->dtt_type = id; if (ctf_type_kind(dmp->dm_ctfp, ctf_type_resolve( dmp->dm_ctfp, id)) != CTF_K_FORWARD) return (0); found++; } } if (found == 0) return (dt_set_errno(dtp, EDT_NOTYPE)); return (0); } int dtrace_symbol_type(dtrace_hdl_t *dtp, const GElf_Sym *symp, const dtrace_syminfo_t *sip, dtrace_typeinfo_t *tip) { dt_module_t *dmp; tip->dtt_object = NULL; tip->dtt_ctfp = NULL; tip->dtt_type = CTF_ERR; if ((dmp = dt_module_lookup_by_name(dtp, sip->dts_object)) == NULL) return (dt_set_errno(dtp, EDT_NOMOD)); if (symp->st_shndx == SHN_UNDEF && dmp->dm_extern != NULL) { dt_ident_t *idp = dt_idhash_lookup(dmp->dm_extern, sip->dts_name); if (idp == NULL) return (dt_set_errno(dtp, EDT_NOSYM)); tip->dtt_ctfp = idp->di_ctfp; tip->dtt_type = idp->di_type; } else if (GELF_ST_TYPE(symp->st_info) != STT_FUNC) { if (dt_module_getctf(dtp, dmp) == NULL) return (-1); /* errno is set for us */ tip->dtt_ctfp = dmp->dm_ctfp; tip->dtt_type = ctf_lookup_by_symbol(dmp->dm_ctfp, sip->dts_id); if (tip->dtt_type == CTF_ERR) { dtp->dt_ctferr = ctf_errno(tip->dtt_ctfp); return (dt_set_errno(dtp, EDT_CTF)); } } else { tip->dtt_ctfp = DT_FPTR_CTFP(dtp); tip->dtt_type = DT_FPTR_TYPE(dtp); } tip->dtt_object = dmp->dm_name; return (0); } static dtrace_objinfo_t * dt_module_info(const dt_module_t *dmp, dtrace_objinfo_t *dto) { dto->dto_name = dmp->dm_name; dto->dto_file = dmp->dm_file; dto->dto_id = dmp->dm_modid; dto->dto_flags = 0; if (dmp->dm_flags & DT_DM_KERNEL) dto->dto_flags |= DTRACE_OBJ_F_KERNEL; if (dmp->dm_flags & DT_DM_PRIMARY) dto->dto_flags |= DTRACE_OBJ_F_PRIMARY; dto->dto_text_va = dmp->dm_text_va; dto->dto_text_size = dmp->dm_text_size; dto->dto_data_va = dmp->dm_data_va; dto->dto_data_size = dmp->dm_data_size; dto->dto_bss_va = dmp->dm_bss_va; dto->dto_bss_size = dmp->dm_bss_size; return (dto); } int dtrace_object_iter(dtrace_hdl_t *dtp, dtrace_obj_f *func, void *data) { const dt_module_t *dmp = dt_list_next(&dtp->dt_modlist); dtrace_objinfo_t dto; int rv; for (; dmp != NULL; dmp = dt_list_next(dmp)) { if ((rv = (*func)(dtp, dt_module_info(dmp, &dto), data)) != 0) return (rv); } return (0); } int dtrace_object_info(dtrace_hdl_t *dtp, const char *object, dtrace_objinfo_t *dto) { dt_module_t *dmp; if (object == DTRACE_OBJ_EVERY || object == DTRACE_OBJ_KMODS || object == DTRACE_OBJ_UMODS || dto == NULL) return (dt_set_errno(dtp, EINVAL)); if ((dmp = dt_module_from_object(dtp, object)) == NULL) return (-1); /* dt_errno is set for us */ if (dt_module_load(dtp, dmp) == -1) return (-1); /* dt_errno is set for us */ (void) dt_module_info(dmp, dto); return (0); }