4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1994, by Sun Microsytems, Inc.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Functions that know how to create and decode combinations that are
30 * used for connecting probe functions.
42 #include <sys/types.h>
44 #include "tnfctl_int.h"
52 typedef struct comb_callinfo
{
54 unsigned shift
; /* shift right <n> bits */
59 typedef struct comb_calltmpl
{
67 typedef struct comb_key
{
74 typedef struct decode_key
{
77 uintptr_t *func_addrs
;
82 * Global - defined in assembler file
84 extern comb_callinfo_t prb_callinfo
;
86 extern void prb_chain_entry(void);
87 extern void prb_chain_down(void);
88 extern void prb_chain_next(void);
89 extern void prb_chain_end(void);
91 static comb_calltmpl_t calltmpl
[PRB_COMB_COUNT
] = {
93 (uintptr_t) prb_chain_entry
,
94 (uintptr_t) prb_chain_down
,
95 (uintptr_t) prb_chain_next
,
96 (uintptr_t) prb_chain_end
}
103 static tnfctl_errcode_t
decode(tnfctl_handle_t
*hndl
, uintptr_t addr
,
104 char ***func_names
, uintptr_t **func_addrs
);
105 static boolean_t
find(tnfctl_handle_t
*hndl
, comb_op_t op
, uintptr_t down
,
106 uintptr_t next
, uintptr_t * comb_p
);
107 static tnfctl_errcode_t
build(tnfctl_handle_t
*hndl
, comb_op_t op
,
108 uintptr_t down
, uintptr_t next
, uintptr_t * comb_p
);
109 static tnfctl_errcode_t
add(tnfctl_handle_t
*hndl
, comb_op_t op
, uintptr_t down
,
110 uintptr_t next
, uintptr_t comb
);
111 static int comb_compare(const void *a
, const void *b
);
112 static int decode_compare(const void *v0p
, const void *v1p
);
113 static tnfctl_errcode_t
iscomb(tnfctl_handle_t
*hndl
, uintptr_t addr
,
114 uintptr_t *down_p
, uintptr_t *next_p
, boolean_t
*ret_val
);
115 static tnfctl_errcode_t
findname(tnfctl_handle_t
*hndl
, uintptr_t addr
,
119 /* ---------------------------------------------------------------- */
120 /* ----------------------- Public Functions ----------------------- */
121 /* ---------------------------------------------------------------- */
124 * _tnfctl_comb_build() - finds (or builds) a combination satisfing the op,
125 * down and next constraints of the caller.
128 _tnfctl_comb_build(tnfctl_handle_t
*hndl
, comb_op_t op
,
129 uintptr_t down
, uintptr_t next
, uintptr_t *comb_p
)
131 tnfctl_errcode_t prexstat
;
135 DBG_TNF_PROBE_0(_tnfctl_comb_build_start
, "libtnfctl",
136 "start _tnfctl_comb_build; sunw%verbosity 1");
138 if (find(hndl
, op
, down
, next
, comb_p
)) {
140 DBG_TNF_PROBE_1(_tnfctl_comb_build_end
, "libtnfctl",
141 "end _tnfctl_comb_build; sunw%verbosity 1",
142 tnf_opaque
, found_comb_at
, *comb_p
);
144 return (TNFCTL_ERR_NONE
);
146 prexstat
= build(hndl
, op
, down
, next
, comb_p
);
148 DBG_TNF_PROBE_1(_tnfctl_comb_build_end
, "libtnfctl",
149 "end _tnfctl_comb_build; sunw%verbosity 1",
150 tnf_opaque
, built_comb_at
, *comb_p
);
157 * _tnfctl_comb_decode() - returns a string describing the probe functions
158 * NOTE - the string is for reference purposes ONLY, it should not be freed
162 _tnfctl_comb_decode(tnfctl_handle_t
*hndl
, uintptr_t addr
, char ***func_names
,
163 uintptr_t **func_addrs
)
165 tnfctl_errcode_t prexstat
;
167 DBG_TNF_PROBE_0(_tnfctl_comb_decode_start
, "libtnfctl",
168 "start _tnfctl_comb_decode; sunw%verbosity 2");
170 prexstat
= decode(hndl
, addr
, func_names
, func_addrs
);
172 DBG_TNF_PROBE_0(_tnfctl_comb_decode_end
, "libtnfctl",
173 "end _tnfctl_comb_decode; sunw%verbosity 2");
179 /* ---------------------------------------------------------------- */
180 /* ----------------------- Private Functions ---------------------- */
181 /* ---------------------------------------------------------------- */
184 * if combination has been decoded, return decoded info., else
185 * decode combination and cache information
187 static tnfctl_errcode_t
188 decode(tnfctl_handle_t
*hndl
, uintptr_t addr
, char ***func_names
,
189 uintptr_t **func_addrs
)
191 tnfctl_errcode_t prexstat
= TNFCTL_ERR_NONE
;
193 decode_key_t
*new_p
= NULL
;
194 decode_key_t
**find_pp
;
197 char *thisname
= NULL
;
198 boolean_t is_combination
;
200 /* see if we can find the previously decoded answer */
202 find_pp
= (decode_key_t
**) tfind(&key
, &hndl
->decoderoot
,
205 DBG_TNF_PROBE_0(decode_1
, "libtnfctl",
206 "sunw%verbosity 2; sunw%debug 'found existing'");
207 *func_names
= (*find_pp
)->name_ptrs
;
208 *func_addrs
= (*find_pp
)->func_addrs
;
209 return (TNFCTL_ERR_NONE
);
212 new_p
= (decode_key_t
*) calloc(1, sizeof (decode_key_t
));
214 return (TNFCTL_ERR_ALLOCFAIL
);
217 prexstat
= iscomb(hndl
, addr
, &down
, &next
, &is_combination
);
221 if (is_combination
) {
223 uintptr_t *nextaddrs
;
228 DBG_TNF_PROBE_2(decode_2
, "libtnfctl", "sunw%verbosity 2;",
229 tnf_opaque
, down
, down
,
230 tnf_opaque
, next
, next
);
232 prexstat
= findname(hndl
, down
, &thisname
);
233 if (prexstat
== TNFCTL_ERR_USR1
) {
235 * should never happen - combination should not
236 * point at the end function
238 prexstat
= TNFCTL_ERR_INTERNAL
;
243 prexstat
= decode(hndl
, next
, &nextnames
, &nextaddrs
);
247 /* count number of elements - caution: empty 'for' loop */
248 for (count
= 0; nextnames
[count
]; count
++);
249 count
++; /* since it was 0 based */
251 /* allocate one more for new function name */
252 new_p
->name_ptrs
= malloc((count
+ 1) *
253 sizeof (new_p
->name_ptrs
[0]));
254 if (new_p
->name_ptrs
== NULL
) {
255 prexstat
= TNFCTL_ERR_ALLOCFAIL
;
258 new_p
->func_addrs
= malloc((count
+ 1) *
259 sizeof (new_p
->func_addrs
[0]));
260 if (new_p
->func_addrs
== NULL
) {
261 prexstat
= TNFCTL_ERR_ALLOCFAIL
;
264 name_pp
= new_p
->name_ptrs
;
265 addr_p
= new_p
->func_addrs
;
267 name_pp
[0] = thisname
;
268 for (j
= 0; j
< count
; j
++) {
269 name_pp
[j
+ 1] = nextnames
[j
];
270 addr_p
[j
+ 1] = nextaddrs
[j
];
273 prexstat
= findname(hndl
, addr
, &thisname
);
274 if (prexstat
!= TNFCTL_ERR_USR1
) {
276 * base case - end function is the only function
277 * that can be pointed at directly
279 if (prexstat
== TNFCTL_ERR_NONE
)
280 prexstat
= TNFCTL_ERR_NONE
;
283 new_p
->name_ptrs
= malloc(sizeof (new_p
->name_ptrs
[0]));
284 if (new_p
->name_ptrs
== NULL
) {
285 prexstat
= TNFCTL_ERR_ALLOCFAIL
;
288 new_p
->func_addrs
= malloc(sizeof (new_p
->func_addrs
[0]));
289 if (new_p
->func_addrs
== NULL
) {
290 prexstat
= TNFCTL_ERR_ALLOCFAIL
;
293 new_p
->name_ptrs
[0] = NULL
;
294 new_p
->func_addrs
[0] = NULL
;
297 DBG_TNF_PROBE_1(decode_3
, "libtnfctl",
298 "sunw%verbosity 2; sunw%debug 'decode built'",
299 tnf_string
, func_name
,
300 (thisname
) ? (thisname
) : "end_func");
302 find_pp
= (decode_key_t
**) tsearch(new_p
,
303 &hndl
->decoderoot
, decode_compare
);
304 assert(*find_pp
== new_p
);
305 *func_names
= new_p
->name_ptrs
;
306 *func_addrs
= new_p
->func_addrs
;
307 return (TNFCTL_ERR_NONE
);
311 if (new_p
->name_ptrs
)
312 free(new_p
->name_ptrs
);
313 if (new_p
->func_addrs
)
314 free(new_p
->func_addrs
);
322 * iscomb() - determine whether the pointed to function is a combination. If
323 * it is, return the down and next pointers
325 static tnfctl_errcode_t
326 iscomb(tnfctl_handle_t
*hndl
,
327 uintptr_t addr
, uintptr_t *down_p
, uintptr_t *next_p
,
331 boolean_t matched
= B_FALSE
;
333 for (type
= 0; type
< PRB_COMB_COUNT
; type
++) {
342 int tmp_bits
= prb_callinfo
.mask
;
344 /* allocate room to copy the target code */
345 size
= (size_t) (calltmpl
[type
].end
- calltmpl
[type
].entry
);
346 targ_p
= (char *) malloc(size
);
348 return (TNFCTL_ERR_ALLOCFAIL
);
350 /* copy code from target */
351 miscstat
= hndl
->p_read(hndl
->proc_p
, addr
, targ_p
, size
);
354 return (TNFCTL_ERR_INTERNAL
);
357 /* find the number of bits before the highest bit in mask */
358 while (tmp_bits
> 0) {
363 /* loop over all the words */
364 tptr
= (char *) calltmpl
[type
].entry
;
365 for (ptr
= targ_p
; ptr
< (targ_p
+ size
); ptr
++, tptr
++) {
368 /* LINTED pointer cast may result in improper alignment */
369 int *uptr
= (int *) ptr
;
372 * If we are pointing at one of the words that we
373 * patch, * (down or next displ) then read that value
374 * in. * Otherwise make sure the words match.
376 if ((uintptr_t) tptr
== calltmpl
[type
].down
+
377 prb_callinfo
.offset
) {
379 downbits
&= prb_callinfo
.mask
;
381 downbits
= (downbits
<< num_bits
) >> num_bits
;
382 downbits
<<= prb_callinfo
.shift
;
383 downaddr
= addr
+ (ptr
- targ_p
) + downbits
;
386 /* intel is relative to *next* instruction */
391 } else if ((uintptr_t) tptr
== calltmpl
[type
].next
+
392 prb_callinfo
.offset
) {
394 nextbits
&= prb_callinfo
.mask
;
396 nextbits
= (nextbits
<< num_bits
) >> num_bits
;
397 nextbits
<<= prb_callinfo
.shift
;
398 nextaddr
= addr
+ (ptr
- targ_p
) + nextbits
;
401 /* intel is relative to *next* instruction */
407 /* the byte better match or we bail */
413 /* YOWSA! - its a match */
417 /* free allocated memory */
425 return (TNFCTL_ERR_NONE
);
430 return (TNFCTL_ERR_NONE
);
434 #define FUNC_BUF_SIZE 32
436 * findname() - find a name for a function given its address.
438 static tnfctl_errcode_t
439 findname(tnfctl_handle_t
*hndl
, uintptr_t addr
, char **ret_name
)
442 tnfctl_errcode_t prexstat
;
445 prexstat
= _tnfctl_sym_findname(hndl
, addr
, &symname
);
446 if ((prexstat
== TNFCTL_ERR_NONE
) && (symname
!= NULL
)) {
451 * If we find "tnf_trace_end" then we should not report it
452 * as this is the "end-cap" function and should be hidden
453 * from the user. Return a null string instead ...
455 if (strcmp(symname
, TRACE_END_FUNC
) == 0) {
456 return (TNFCTL_ERR_USR1
);
459 return (TNFCTL_ERR_NONE
);
464 buffer
= malloc(FUNC_BUF_SIZE
);
466 return (TNFCTL_ERR_ALLOCFAIL
);
468 /* no name found, use the address */
469 (void) sprintf(buffer
, "func@0x%p", addr
);
471 return (TNFCTL_ERR_NONE
);
477 * find() - try to find an existing combination that satisfies ...
480 find(tnfctl_handle_t
*hndl
, comb_op_t op
, uintptr_t down
, uintptr_t next
,
484 comb_key_t
**find_pp
;
491 find_pp
= (comb_key_t
**) tfind(&key
, &hndl
->buildroot
, comb_compare
);
493 *comb_p
= (*find_pp
)->comb
;
501 * add() - adds a combination to combination cache
503 static tnfctl_errcode_t
504 add(tnfctl_handle_t
*hndl
, comb_op_t op
, uintptr_t down
, uintptr_t next
,
508 /* LINTED set but not used in function */
511 new_p
= (comb_key_t
*) malloc(sizeof (comb_key_t
));
513 return (TNFCTL_ERR_ALLOCFAIL
);
520 ret_pp
= (comb_key_t
**) tsearch(new_p
, &hndl
->buildroot
,
522 assert(*ret_pp
== new_p
);
523 return (TNFCTL_ERR_NONE
);
528 * decode_compare() - comparison function used for tree search for
532 decode_compare(const void *v0p
, const void *v1p
)
534 decode_key_t
*k0p
= (decode_key_t
*) v0p
;
535 decode_key_t
*k1p
= (decode_key_t
*) v1p
;
537 return (int) ((uintptr_t) k1p
->addr
- (uintptr_t) k0p
->addr
);
538 } /* end decode_compare */
542 * comb_compare() - comparison function used for tree search for combinations
545 comb_compare(const void *v0p
, const void *v1p
)
547 comb_key_t
*k0p
= (comb_key_t
*) v0p
;
548 comb_key_t
*k1p
= (comb_key_t
*) v1p
;
550 if (k0p
->op
!= k1p
->op
)
551 return ((k0p
->op
< k1p
->op
) ? -1 : 1);
553 if (k0p
->down
!= k1p
->down
)
554 return ((k0p
->down
< k1p
->down
) ? -1 : 1);
556 if (k0p
->next
!= k1p
->next
)
557 return ((k0p
->next
< k1p
->next
) ? -1 : 1);
561 } /* end comb_compare */
564 * build() - build a composition
566 static tnfctl_errcode_t
567 build(tnfctl_handle_t
*hndl
, comb_op_t op
, uintptr_t down
, uintptr_t next
,
572 char *buffer_p
= NULL
;
577 tnfctl_errcode_t prexstat
;
580 (void) fprintf(stderr
, "off=0x%x shift=0x%x mask=0x%x size=%d\n",
584 calltmpl
[op
].end
- calltmpl
[op
].entry
);
588 size
= calltmpl
[op
].end
- calltmpl
[op
].entry
;
590 /* allocate memory in the target process */
591 prexstat
= _tnfctl_targmem_alloc(hndl
, size
, &addr
);
593 DBG((void) fprintf(stderr
,
594 "build: trouble allocating target memory:\n"));
598 /* allocate a scratch buffer, copy the template into it */
599 buffer_p
= malloc(size
);
601 DBG((void) fprintf(stderr
, "build: alloc failed\n"));
602 prexstat
= TNFCTL_ERR_ALLOCFAIL
;
605 (void) memcpy(buffer_p
, (void *) calltmpl
[op
].entry
, size
);
607 /* poke the down address */
608 offset
= calltmpl
[op
].down
- calltmpl
[op
].entry
;
609 /*LINTED pointer cast may result in improper alignment*/
610 word_p
= (unsigned *) (buffer_p
+ offset
+ prb_callinfo
.offset
);
611 contents
= down
- (addr
+ offset
);
613 contents
-= 5; /* intel offset is relative to *next* instr */
616 DBG_TNF_PROBE_4(build_1
, "libtnfctl", "sunw%verbosity 3",
617 tnf_opaque
, down
, down
,
618 tnf_opaque
, contents
, contents
,
619 tnf_opaque
, word_p
, word_p
,
620 tnf_long
, offset
, offset
);
622 *word_p
&= ~prb_callinfo
.mask
; /* clear the relevant field */
623 *word_p
|= ((contents
>> prb_callinfo
.shift
) & prb_callinfo
.mask
);
625 /* poke the next address */
626 offset
= calltmpl
[op
].next
- calltmpl
[op
].entry
;
627 /*LINTED pointer cast may result in improper alignment*/
628 word_p
= (unsigned *) (buffer_p
+ offset
+ prb_callinfo
.offset
);
629 contents
= next
- (addr
+ offset
);
631 contents
-= 5; /* intel offset is relative to *next* instr */
634 DBG_TNF_PROBE_4(build_2
, "libtnfctl", "sunw%verbosity 3",
635 tnf_opaque
, next
, next
,
636 tnf_opaque
, contents
, contents
,
637 tnf_opaque
, word_p
, word_p
,
638 tnf_long
, offset
, offset
);
640 *word_p
&= ~prb_callinfo
.mask
; /* clear the relevant field */
641 *word_p
|= ((contents
>> prb_callinfo
.shift
) & prb_callinfo
.mask
);
643 /* copy the combination template into target memory */
644 miscstat
= hndl
->p_write(hndl
->proc_p
, addr
, buffer_p
, size
);
646 DBG((void) fprintf(stderr
,
647 "build: trouble writing combination: \n"));
648 prexstat
= TNFCTL_ERR_INTERNAL
;
652 prexstat
= add(hndl
, op
, down
, next
, addr
);