4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012 by Delphix. All rights reserved.
27 #include <sys/sysmacros.h>
47 } dtrace_probespecs
[] = {
48 { offsetof(dtrace_probedesc_t
, dtpd_provider
), DTRACE_PROVNAMELEN
},
49 { offsetof(dtrace_probedesc_t
, dtpd_mod
), DTRACE_MODNAMELEN
},
50 { offsetof(dtrace_probedesc_t
, dtpd_func
), DTRACE_FUNCNAMELEN
},
51 { offsetof(dtrace_probedesc_t
, dtpd_name
), DTRACE_NAMELEN
}
55 dtrace_xstr2desc(dtrace_hdl_t
*dtp
, dtrace_probespec_t spec
,
56 const char *s
, int argc
, char *const argv
[], dtrace_probedesc_t
*pdp
)
58 size_t off
, len
, vlen
, wlen
;
59 const char *p
, *q
, *v
, *w
;
61 char buf
[32]; /* for id_t as %d (see below) */
63 if (spec
< DTRACE_PROBESPEC_NONE
|| spec
> DTRACE_PROBESPEC_NAME
)
64 return (dt_set_errno(dtp
, EINVAL
));
66 bzero(pdp
, sizeof (dtrace_probedesc_t
));
67 p
= s
+ strlen(s
) - 1;
70 for (len
= 0; p
>= s
&& *p
!= ':'; len
++)
71 p
--; /* move backward until we find a delimiter */
78 if ((v
= strchr(q
, '$')) != NULL
&& v
< q
+ len
) {
80 * Set vlen to the length of the variable name and then
81 * reset len to the length of the text prior to '$'. If
82 * the name begins with a digit, interpret it using the
83 * the argv[] array. Otherwise we look in dt_macros.
84 * For the moment, all dt_macros variables are of type
85 * id_t (see dtrace_update() for more details on that).
87 vlen
= (size_t)(q
+ len
- v
);
88 len
= (size_t)(v
- q
);
91 * If the variable string begins with $$, skip past the
92 * leading dollar sign since $ and $$ are equivalent
93 * macro reference operators in a probe description.
95 if (vlen
> 2 && v
[1] == '$') {
104 i
= strtol(v
+ 1, (char **)&w
, 10);
106 wlen
= vlen
- (w
- v
);
108 if (i
< 0 || i
>= argc
|| errno
!= 0)
109 return (dt_set_errno(dtp
, EDT_BADSPCV
));
114 if (yypcb
!= NULL
&& yypcb
->pcb_sargv
== argv
)
115 yypcb
->pcb_sflagv
[i
] |= DT_IDFLG_REF
;
117 } else if (vlen
> 1) {
118 char *vstr
= alloca(vlen
);
121 (void) strncpy(vstr
, v
+ 1, vlen
- 1);
122 vstr
[vlen
- 1] = '\0';
123 idp
= dt_idhash_lookup(dtp
->dt_macros
, vstr
);
126 return (dt_set_errno(dtp
, EDT_BADSPCV
));
129 vlen
= snprintf(buf
, 32, "%d", idp
->di_id
);
132 return (dt_set_errno(dtp
, EDT_BADSPCV
));
135 if (spec
== DTRACE_PROBESPEC_NONE
)
136 return (dt_set_errno(dtp
, EDT_BADSPEC
));
138 if (len
+ vlen
>= dtrace_probespecs
[spec
].dtps_len
)
139 return (dt_set_errno(dtp
, ENAMETOOLONG
));
141 off
= dtrace_probespecs
[spec
--].dtps_offset
;
142 bcopy(q
, (char *)pdp
+ off
, len
);
143 bcopy(v
, (char *)pdp
+ off
+ len
, vlen
);
144 bcopy(w
, (char *)pdp
+ off
+ len
+ vlen
, wlen
);
147 pdp
->dtpd_id
= DTRACE_IDNONE
;
152 dtrace_str2desc(dtrace_hdl_t
*dtp
, dtrace_probespec_t spec
,
153 const char *s
, dtrace_probedesc_t
*pdp
)
155 return (dtrace_xstr2desc(dtp
, spec
, s
, 0, NULL
, pdp
));
159 dtrace_id2desc(dtrace_hdl_t
*dtp
, dtrace_id_t id
, dtrace_probedesc_t
*pdp
)
161 bzero(pdp
, sizeof (dtrace_probedesc_t
));
164 if (dt_ioctl(dtp
, DTRACEIOC_PROBES
, pdp
) == -1 ||
166 return (dt_set_errno(dtp
, EDT_BADID
));
172 dtrace_desc2str(const dtrace_probedesc_t
*pdp
, char *buf
, size_t len
)
174 if (pdp
->dtpd_id
== 0) {
175 (void) snprintf(buf
, len
, "%s:%s:%s:%s", pdp
->dtpd_provider
,
176 pdp
->dtpd_mod
, pdp
->dtpd_func
, pdp
->dtpd_name
);
178 (void) snprintf(buf
, len
, "%u", pdp
->dtpd_id
);
184 dtrace_attr2str(dtrace_attribute_t attr
, char *buf
, size_t len
)
186 const char *name
= dtrace_stability_name(attr
.dtat_name
);
187 const char *data
= dtrace_stability_name(attr
.dtat_data
);
188 const char *class = dtrace_class_name(attr
.dtat_class
);
190 if (name
== NULL
|| data
== NULL
|| class == NULL
)
191 return (NULL
); /* one or more invalid attributes */
193 (void) snprintf(buf
, len
, "%s/%s/%s", name
, data
, class);
198 dt_getstrattr(char *p
, char **qp
)
205 if ((q
= strchr(p
, '/')) == NULL
)
215 dtrace_str2attr(const char *str
, dtrace_attribute_t
*attr
)
217 dtrace_stability_t s
;
221 if (str
== NULL
|| attr
== NULL
)
222 return (-1); /* invalid function arguments */
224 *attr
= _dtrace_maxattr
;
227 if ((p
= dt_getstrattr(p
, &q
)) == NULL
)
230 for (s
= 0; s
<= DTRACE_STABILITY_MAX
; s
++) {
231 if (strcasecmp(p
, dtrace_stability_name(s
)) == 0) {
237 if (s
> DTRACE_STABILITY_MAX
)
240 if ((p
= dt_getstrattr(q
, &q
)) == NULL
)
243 for (s
= 0; s
<= DTRACE_STABILITY_MAX
; s
++) {
244 if (strcasecmp(p
, dtrace_stability_name(s
)) == 0) {
250 if (s
> DTRACE_STABILITY_MAX
)
253 if ((p
= dt_getstrattr(q
, &q
)) == NULL
)
256 for (c
= 0; c
<= DTRACE_CLASS_MAX
; c
++) {
257 if (strcasecmp(p
, dtrace_class_name(c
)) == 0) {
258 attr
->dtat_class
= c
;
263 if (c
> DTRACE_CLASS_MAX
|| (p
= dt_getstrattr(q
, &q
)) != NULL
)
270 dtrace_stability_name(dtrace_stability_t s
)
273 case DTRACE_STABILITY_INTERNAL
: return ("Internal");
274 case DTRACE_STABILITY_PRIVATE
: return ("Private");
275 case DTRACE_STABILITY_OBSOLETE
: return ("Obsolete");
276 case DTRACE_STABILITY_EXTERNAL
: return ("External");
277 case DTRACE_STABILITY_UNSTABLE
: return ("Unstable");
278 case DTRACE_STABILITY_EVOLVING
: return ("Evolving");
279 case DTRACE_STABILITY_STABLE
: return ("Stable");
280 case DTRACE_STABILITY_STANDARD
: return ("Standard");
281 default: return (NULL
);
286 dtrace_class_name(dtrace_class_t c
)
289 case DTRACE_CLASS_UNKNOWN
: return ("Unknown");
290 case DTRACE_CLASS_CPU
: return ("CPU");
291 case DTRACE_CLASS_PLATFORM
: return ("Platform");
292 case DTRACE_CLASS_GROUP
: return ("Group");
293 case DTRACE_CLASS_ISA
: return ("ISA");
294 case DTRACE_CLASS_COMMON
: return ("Common");
295 default: return (NULL
);
300 dt_attr_min(dtrace_attribute_t a1
, dtrace_attribute_t a2
)
302 dtrace_attribute_t am
;
304 am
.dtat_name
= MIN(a1
.dtat_name
, a2
.dtat_name
);
305 am
.dtat_data
= MIN(a1
.dtat_data
, a2
.dtat_data
);
306 am
.dtat_class
= MIN(a1
.dtat_class
, a2
.dtat_class
);
312 dt_attr_max(dtrace_attribute_t a1
, dtrace_attribute_t a2
)
314 dtrace_attribute_t am
;
316 am
.dtat_name
= MAX(a1
.dtat_name
, a2
.dtat_name
);
317 am
.dtat_data
= MAX(a1
.dtat_data
, a2
.dtat_data
);
318 am
.dtat_class
= MAX(a1
.dtat_class
, a2
.dtat_class
);
324 * Compare two attributes and return an integer value in the following ranges:
326 * <0 if any of a1's attributes are less than a2's attributes
327 * =0 if all of a1's attributes are equal to a2's attributes
328 * >0 if all of a1's attributes are greater than or equal to a2's attributes
330 * To implement this function efficiently, we subtract a2's attributes from
331 * a1's to obtain a negative result if an a1 attribute is less than its a2
332 * counterpart. We then OR the intermediate results together, relying on the
333 * twos-complement property that if any result is negative, the bitwise union
334 * will also be negative since the highest bit will be set in the result.
337 dt_attr_cmp(dtrace_attribute_t a1
, dtrace_attribute_t a2
)
339 return (((int)a1
.dtat_name
- a2
.dtat_name
) |
340 ((int)a1
.dtat_data
- a2
.dtat_data
) |
341 ((int)a1
.dtat_class
- a2
.dtat_class
));
345 dt_attr_str(dtrace_attribute_t a
, char *buf
, size_t len
)
347 static const char stability
[] = "ipoxuesS";
348 static const char class[] = "uCpgIc";
350 if (a
.dtat_name
< sizeof (stability
) &&
351 a
.dtat_data
< sizeof (stability
) && a
.dtat_class
< sizeof (class)) {
352 (void) snprintf(buf
, len
, "[%c/%c/%c]", stability
[a
.dtat_name
],
353 stability
[a
.dtat_data
], class[a
.dtat_class
]);
355 (void) snprintf(buf
, len
, "[%u/%u/%u]",
356 a
.dtat_name
, a
.dtat_data
, a
.dtat_class
);
363 dt_version_num2str(dt_version_t v
, char *buf
, size_t len
)
365 uint_t M
= DT_VERSION_MAJOR(v
);
366 uint_t m
= DT_VERSION_MINOR(v
);
367 uint_t u
= DT_VERSION_MICRO(v
);
370 (void) snprintf(buf
, len
, "%u.%u", M
, m
);
372 (void) snprintf(buf
, len
, "%u.%u.%u", M
, m
, u
);
378 dt_version_str2num(const char *s
, dt_version_t
*vp
)
380 int i
= 0, n
[3] = { 0, 0, 0 };
383 while ((c
= *s
++) != '\0') {
385 n
[i
] = n
[i
] * 10 + c
- '0';
386 else if (c
!= '.' || i
++ >= sizeof (n
) / sizeof (n
[0]) - 1)
390 if (n
[0] > DT_VERSION_MAJMAX
||
391 n
[1] > DT_VERSION_MINMAX
||
392 n
[2] > DT_VERSION_MICMAX
)
396 *vp
= DT_VERSION_NUMBER(n
[0], n
[1], n
[2]);
402 dt_version_defined(dt_version_t v
)
406 for (i
= 0; _dtrace_versions
[i
] != 0; i
++) {
407 if (_dtrace_versions
[i
] == v
)
415 dt_cpp_add_arg(dtrace_hdl_t
*dtp
, const char *str
)
419 if (dtp
->dt_cpp_argc
== dtp
->dt_cpp_args
) {
420 int olds
= dtp
->dt_cpp_args
;
422 char **argv
= realloc(dtp
->dt_cpp_argv
, sizeof (char *) * news
);
427 bzero(&argv
[olds
], sizeof (char *) * olds
);
428 dtp
->dt_cpp_argv
= argv
;
429 dtp
->dt_cpp_args
= news
;
432 if ((arg
= strdup(str
)) == NULL
)
435 assert(dtp
->dt_cpp_argc
< dtp
->dt_cpp_args
);
436 dtp
->dt_cpp_argv
[dtp
->dt_cpp_argc
++] = arg
;
441 dt_cpp_pop_arg(dtrace_hdl_t
*dtp
)
445 if (dtp
->dt_cpp_argc
<= 1)
446 return (NULL
); /* dt_cpp_argv[0] cannot be popped */
448 arg
= dtp
->dt_cpp_argv
[--dtp
->dt_cpp_argc
];
449 dtp
->dt_cpp_argv
[dtp
->dt_cpp_argc
] = NULL
;
456 dt_dprintf(const char *format
, ...)
461 va_start(alist
, format
);
462 (void) fputs("libdtrace DEBUG: ", stderr
);
463 (void) vfprintf(stderr
, format
, alist
);
469 dt_ioctl(dtrace_hdl_t
*dtp
, int val
, void *arg
)
471 const dtrace_vector_t
*v
= dtp
->dt_vector
;
474 return (v
->dtv_ioctl(dtp
->dt_varg
, val
, arg
));
477 return (ioctl(dtp
->dt_fd
, val
, arg
));
484 dt_status(dtrace_hdl_t
*dtp
, processorid_t cpu
)
486 const dtrace_vector_t
*v
= dtp
->dt_vector
;
489 return (p_online(cpu
, P_STATUS
));
491 return (v
->dtv_status(dtp
->dt_varg
, cpu
));
495 dt_sysconf(dtrace_hdl_t
*dtp
, int name
)
497 const dtrace_vector_t
*v
= dtp
->dt_vector
;
500 return (sysconf(name
));
502 return (v
->dtv_sysconf(dtp
->dt_varg
, name
));
506 * Wrapper around write(2) to handle partial writes. For maximum safety of
507 * output files and proper error reporting, we continuing writing in the
508 * face of partial writes until write(2) fails or 'buf' is completely written.
509 * We also record any errno in the specified dtrace_hdl_t as well as 'errno'.
512 dt_write(dtrace_hdl_t
*dtp
, int fd
, const void *buf
, size_t n
)
518 if ((len
= write(fd
, buf
, resid
)) <= 0)
522 buf
= (char *)buf
+ len
;
525 if (resid
== n
&& n
!= 0)
526 return (dt_set_errno(dtp
, errno
));
532 * This function handles all output from libdtrace, as well as the
533 * dtrace_sprintf() case. If we're here due to dtrace_sprintf(), then
534 * dt_sprintf_buflen will be non-zero; in this case, we sprintf into the
535 * specified buffer and return. Otherwise, if output is buffered (denoted by
536 * a NULL fp), we sprintf the desired output into the buffered buffer
537 * (expanding the buffer if required). If we don't satisfy either of these
538 * conditions (that is, if we are to actually generate output), then we call
539 * fprintf with the specified fp. In this case, we need to deal with one of
540 * the more annoying peculiarities of libc's printf routines: any failed
541 * write persistently sets an error flag inside the FILE causing every
542 * subsequent write to fail, but only the caller that initiated the error gets
543 * the errno. Since libdtrace clients often intercept SIGINT, this case is
544 * particularly frustrating since we don't want the EINTR on one attempt to
545 * write to the output file to preclude later attempts to write. This
546 * function therefore does a clearerr() if any error occurred, and saves the
547 * errno for the caller inside the specified dtrace_hdl_t.
551 dt_printf(dtrace_hdl_t
*dtp
, FILE *fp
, const char *format
, ...)
556 va_start(ap
, format
);
558 if (dtp
->dt_sprintf_buflen
!= 0) {
562 assert(dtp
->dt_sprintf_buf
!= NULL
);
564 buf
= &dtp
->dt_sprintf_buf
[len
= strlen(dtp
->dt_sprintf_buf
)];
565 len
= dtp
->dt_sprintf_buflen
- len
;
568 if ((n
= vsnprintf(buf
, len
, format
, ap
)) < 0)
569 n
= dt_set_errno(dtp
, errno
);
581 * Using buffered output is not allowed if a handler has
582 * not been installed.
584 if (dtp
->dt_bufhdlr
== NULL
) {
586 return (dt_set_errno(dtp
, EDT_NOBUFFERED
));
589 if (dtp
->dt_buffered_buf
== NULL
) {
590 assert(dtp
->dt_buffered_size
== 0);
591 dtp
->dt_buffered_size
= 1;
592 dtp
->dt_buffered_buf
= malloc(dtp
->dt_buffered_size
);
594 if (dtp
->dt_buffered_buf
== NULL
) {
596 return (dt_set_errno(dtp
, EDT_NOMEM
));
599 dtp
->dt_buffered_offs
= 0;
600 dtp
->dt_buffered_buf
[0] = '\0';
603 if ((needed
= vsnprintf(NULL
, 0, format
, ap
)) < 0) {
604 rval
= dt_set_errno(dtp
, errno
);
617 assert(dtp
->dt_buffered_offs
< dtp
->dt_buffered_size
);
618 avail
= dtp
->dt_buffered_size
- dtp
->dt_buffered_offs
;
620 if (needed
+ 1 < avail
)
623 if ((newbuf
= realloc(dtp
->dt_buffered_buf
,
624 dtp
->dt_buffered_size
<< 1)) == NULL
) {
626 return (dt_set_errno(dtp
, EDT_NOMEM
));
629 dtp
->dt_buffered_buf
= newbuf
;
630 dtp
->dt_buffered_size
<<= 1;
633 if (vsnprintf(&dtp
->dt_buffered_buf
[dtp
->dt_buffered_offs
],
634 avail
, format
, ap
) < 0) {
635 rval
= dt_set_errno(dtp
, errno
);
640 dtp
->dt_buffered_offs
+= needed
;
641 assert(dtp
->dt_buffered_buf
[dtp
->dt_buffered_offs
] == '\0');
645 n
= vfprintf(fp
, format
, ap
);
650 return (dt_set_errno(dtp
, errno
));
657 dt_buffered_flush(dtrace_hdl_t
*dtp
, dtrace_probedata_t
*pdata
,
658 const dtrace_recdesc_t
*rec
, const dtrace_aggdata_t
*agg
, uint32_t flags
)
660 dtrace_bufdata_t data
;
662 if (dtp
->dt_buffered_offs
== 0)
665 data
.dtbda_handle
= dtp
;
666 data
.dtbda_buffered
= dtp
->dt_buffered_buf
;
667 data
.dtbda_probe
= pdata
;
668 data
.dtbda_recdesc
= rec
;
669 data
.dtbda_aggdata
= agg
;
670 data
.dtbda_flags
= flags
;
672 if ((*dtp
->dt_bufhdlr
)(&data
, dtp
->dt_bufarg
) == DTRACE_HANDLE_ABORT
)
673 return (dt_set_errno(dtp
, EDT_DIRABORT
));
675 dtp
->dt_buffered_offs
= 0;
676 dtp
->dt_buffered_buf
[0] = '\0';
682 dt_buffered_destroy(dtrace_hdl_t
*dtp
)
684 free(dtp
->dt_buffered_buf
);
685 dtp
->dt_buffered_buf
= NULL
;
686 dtp
->dt_buffered_offs
= 0;
687 dtp
->dt_buffered_size
= 0;
691 dt_zalloc(dtrace_hdl_t
*dtp
, size_t size
)
695 if ((data
= malloc(size
)) == NULL
)
696 (void) dt_set_errno(dtp
, EDT_NOMEM
);
704 dt_alloc(dtrace_hdl_t
*dtp
, size_t size
)
708 if ((data
= malloc(size
)) == NULL
)
709 (void) dt_set_errno(dtp
, EDT_NOMEM
);
715 dt_free(dtrace_hdl_t
*dtp
, void *data
)
717 assert(dtp
!= NULL
); /* ensure sane use of this interface */
722 dt_difo_free(dtrace_hdl_t
*dtp
, dtrace_difo_t
*dp
)
725 return; /* simplify caller code */
727 dt_free(dtp
, dp
->dtdo_buf
);
728 dt_free(dtp
, dp
->dtdo_inttab
);
729 dt_free(dtp
, dp
->dtdo_strtab
);
730 dt_free(dtp
, dp
->dtdo_vartab
);
731 dt_free(dtp
, dp
->dtdo_kreltab
);
732 dt_free(dtp
, dp
->dtdo_ureltab
);
733 dt_free(dtp
, dp
->dtdo_xlmtab
);
739 * dt_gmatch() is similar to gmatch(3GEN) and dtrace(7D) globbing, but also
740 * implements the behavior that an empty pattern matches any string.
743 dt_gmatch(const char *s
, const char *p
)
745 return (p
== NULL
|| *p
== '\0' || gmatch(s
, p
));
749 dt_basename(char *str
)
751 char *last
= strrchr(str
, '/');
760 * dt_popc() is a fast implementation of population count. The algorithm is
761 * from "Hacker's Delight" by Henry Warren, Jr with a 64-bit equivalent added.
767 x
= x
- ((x
>> 1) & 0x55555555UL
);
768 x
= (x
& 0x33333333UL
) + ((x
>> 2) & 0x33333333UL
);
769 x
= (x
+ (x
>> 4)) & 0x0F0F0F0FUL
;
775 x
= x
- ((x
>> 1) & 0x5555555555555555ULL
);
776 x
= (x
& 0x3333333333333333ULL
) + ((x
>> 2) & 0x3333333333333333ULL
);
777 x
= (x
+ (x
>> 4)) & 0x0F0F0F0F0F0F0F0FULL
;
786 * dt_popcb() is a bitmap-based version of population count that returns the
787 * number of one bits in the specified bitmap 'bp' at bit positions below 'n'.
790 dt_popcb(const ulong_t
*bp
, ulong_t n
)
792 ulong_t maxb
= n
& BT_ULMASK
;
793 ulong_t maxw
= n
>> BT_ULSHIFT
;
799 for (w
= 0; w
< maxw
; w
++)
800 popc
+= dt_popc(bp
[w
]);
802 return (popc
+ dt_popc(bp
[maxw
] & ((1UL << maxb
) - 1)));
806 dt_string2str(char *s
, char *str
, int nbytes
)
812 * Like snprintf(3C), we don't check the value of str if the
813 * number of bytes is 0.
819 (void) strncpy(str
, s
, nbytes
- 1);
821 * Like snprintf(3C) (and unlike strncpy(3C)), we guarantee
822 * that the string is null-terminated.
824 str
[nbytes
- 1] = '\0';
826 (void) strcpy(str
, s
);
833 dtrace_addr2str(dtrace_hdl_t
*dtp
, uint64_t addr
, char *str
, int nbytes
)
835 dtrace_syminfo_t dts
;
838 size_t n
= 20; /* for 0x%llx\0 */
842 if ((err
= dtrace_lookup_by_addr(dtp
, addr
, &sym
, &dts
)) == 0)
843 n
+= strlen(dts
.dts_object
) + strlen(dts
.dts_name
) + 2; /* +` */
847 if (err
== 0 && addr
!= sym
.st_value
) {
848 (void) snprintf(s
, n
, "%s`%s+0x%llx", dts
.dts_object
,
849 dts
.dts_name
, (u_longlong_t
)addr
- sym
.st_value
);
850 } else if (err
== 0) {
851 (void) snprintf(s
, n
, "%s`%s",
852 dts
.dts_object
, dts
.dts_name
);
855 * We'll repeat the lookup, but this time we'll specify a NULL
856 * GElf_Sym -- indicating that we're only interested in the
859 if (dtrace_lookup_by_addr(dtp
, addr
, NULL
, &dts
) == 0) {
860 (void) snprintf(s
, n
, "%s`0x%llx", dts
.dts_object
,
863 (void) snprintf(s
, n
, "0x%llx", (u_longlong_t
)addr
);
867 return (dt_string2str(s
, str
, nbytes
));
871 dtrace_uaddr2str(dtrace_hdl_t
*dtp
, pid_t pid
,
872 uint64_t addr
, char *str
, int nbytes
)
874 char name
[PATH_MAX
], objname
[PATH_MAX
], c
[PATH_MAX
* 2];
875 struct ps_prochandle
*P
= NULL
;
880 P
= dt_proc_grab(dtp
, pid
, PGRAB_RDONLY
| PGRAB_FORCE
, 0);
883 (void) snprintf(c
, sizeof (c
), "0x%llx", addr
);
884 return (dt_string2str(c
, str
, nbytes
));
887 dt_proc_lock(dtp
, P
);
889 if (Plookup_by_addr(P
, addr
, name
, sizeof (name
), &sym
) == 0) {
890 (void) Pobjname(P
, addr
, objname
, sizeof (objname
));
892 obj
= dt_basename(objname
);
894 if (addr
> sym
.st_value
) {
895 (void) snprintf(c
, sizeof (c
), "%s`%s+0x%llx", obj
,
896 name
, (u_longlong_t
)(addr
- sym
.st_value
));
898 (void) snprintf(c
, sizeof (c
), "%s`%s", obj
, name
);
900 } else if (Pobjname(P
, addr
, objname
, sizeof (objname
)) != NULL
) {
901 (void) snprintf(c
, sizeof (c
), "%s`0x%llx",
902 dt_basename(objname
), addr
);
904 (void) snprintf(c
, sizeof (c
), "0x%llx", addr
);
907 dt_proc_unlock(dtp
, P
);
908 dt_proc_release(dtp
, P
);
910 return (dt_string2str(c
, str
, nbytes
));