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.
27 * Functions that know how to create and decode combinations that are
28 * used for connecting probe functions.
40 #include <sys/types.h>
42 #include "tnfctl_int.h"
50 typedef struct comb_callinfo
{
52 unsigned shift
; /* shift right <n> bits */
57 typedef struct comb_calltmpl
{
65 typedef struct comb_key
{
72 typedef struct decode_key
{
75 uintptr_t *func_addrs
;
80 * Global - defined in assembler file
82 extern comb_callinfo_t prb_callinfo
;
84 extern void prb_chain_entry(void);
85 extern void prb_chain_down(void);
86 extern void prb_chain_next(void);
87 extern void prb_chain_end(void);
89 static comb_calltmpl_t calltmpl
[PRB_COMB_COUNT
] = {
91 (uintptr_t)prb_chain_entry
,
92 (uintptr_t)prb_chain_down
,
93 (uintptr_t)prb_chain_next
,
94 (uintptr_t)prb_chain_end
}
101 static tnfctl_errcode_t
decode(tnfctl_handle_t
*hndl
, uintptr_t addr
,
102 char ***func_names
, uintptr_t **func_addrs
);
103 static boolean_t
find(tnfctl_handle_t
*hndl
, comb_op_t op
, uintptr_t down
,
104 uintptr_t next
, uintptr_t *comb_p
);
105 static tnfctl_errcode_t
build(tnfctl_handle_t
*hndl
, comb_op_t op
,
106 uintptr_t down
, uintptr_t next
, uintptr_t *comb_p
);
107 static tnfctl_errcode_t
add(tnfctl_handle_t
*hndl
, comb_op_t op
, uintptr_t down
,
108 uintptr_t next
, uintptr_t comb
);
109 static int comb_compare(const void *a
, const void *b
);
110 static int decode_compare(const void *v0p
, const void *v1p
);
111 static tnfctl_errcode_t
iscomb(tnfctl_handle_t
*hndl
, uintptr_t addr
,
112 uintptr_t *down_p
, uintptr_t *next_p
, boolean_t
*ret_val
);
113 static tnfctl_errcode_t
findname(tnfctl_handle_t
*hndl
, uintptr_t addr
,
117 /* ---------------------------------------------------------------- */
118 /* ----------------------- Public Functions ----------------------- */
119 /* ---------------------------------------------------------------- */
122 * _tnfctl_comb_build() - finds (or builds) a combination satisfing the op,
123 * down and next constraints of the caller.
126 _tnfctl_comb_build(tnfctl_handle_t
*hndl
, comb_op_t op
,
127 uintptr_t down
, uintptr_t next
, uintptr_t *comb_p
)
129 tnfctl_errcode_t prexstat
;
133 DBG_TNF_PROBE_0(_tnfctl_comb_build_start
, "libtnfctl",
134 "start _tnfctl_comb_build; sunw%verbosity 1");
136 if (find(hndl
, op
, down
, next
, comb_p
)) {
138 DBG_TNF_PROBE_1(_tnfctl_comb_build_end
, "libtnfctl",
139 "end _tnfctl_comb_build; sunw%verbosity 1",
140 tnf_opaque
, found_comb_at
, *comb_p
);
142 return (TNFCTL_ERR_NONE
);
144 prexstat
= build(hndl
, op
, down
, next
, comb_p
);
146 DBG_TNF_PROBE_1(_tnfctl_comb_build_end
, "libtnfctl",
147 "end _tnfctl_comb_build; sunw%verbosity 1",
148 tnf_opaque
, built_comb_at
, *comb_p
);
155 * _tnfctl_comb_decode() - returns a string describing the probe functions
156 * NOTE - the string is for reference purposes ONLY, it should not be freed
160 _tnfctl_comb_decode(tnfctl_handle_t
*hndl
, uintptr_t addr
, char ***func_names
,
161 uintptr_t **func_addrs
)
163 tnfctl_errcode_t prexstat
;
165 DBG_TNF_PROBE_0(_tnfctl_comb_decode_start
, "libtnfctl",
166 "start _tnfctl_comb_decode; sunw%verbosity 2");
168 prexstat
= decode(hndl
, addr
, func_names
, func_addrs
);
170 DBG_TNF_PROBE_0(_tnfctl_comb_decode_end
, "libtnfctl",
171 "end _tnfctl_comb_decode; sunw%verbosity 2");
177 /* ---------------------------------------------------------------- */
178 /* ----------------------- Private Functions ---------------------- */
179 /* ---------------------------------------------------------------- */
182 * if combination has been decoded, return decoded info., else
183 * decode combination and cache information
185 static tnfctl_errcode_t
186 decode(tnfctl_handle_t
*hndl
, uintptr_t addr
, char ***func_names
,
187 uintptr_t **func_addrs
)
189 tnfctl_errcode_t prexstat
= TNFCTL_ERR_NONE
;
191 decode_key_t
*new_p
= NULL
;
192 decode_key_t
**find_pp
;
195 char *thisname
= NULL
;
196 boolean_t is_combination
;
198 /* see if we can find the previously decoded answer */
200 find_pp
= (decode_key_t
**)tfind(&key
, &hndl
->decoderoot
,
203 DBG_TNF_PROBE_0(decode_1
, "libtnfctl",
204 "sunw%verbosity 2; sunw%debug 'found existing'");
205 *func_names
= (*find_pp
)->name_ptrs
;
206 *func_addrs
= (*find_pp
)->func_addrs
;
207 return (TNFCTL_ERR_NONE
);
210 new_p
= calloc(1, sizeof (decode_key_t
));
212 return (TNFCTL_ERR_ALLOCFAIL
);
215 prexstat
= iscomb(hndl
, addr
, &down
, &next
, &is_combination
);
219 if (is_combination
) {
221 uintptr_t *nextaddrs
;
226 DBG_TNF_PROBE_2(decode_2
, "libtnfctl", "sunw%verbosity 2;",
227 tnf_opaque
, down
, down
, tnf_opaque
, next
, next
);
229 prexstat
= findname(hndl
, down
, &thisname
);
230 if (prexstat
== TNFCTL_ERR_USR1
) {
232 * should never happen - combination should not
233 * point at the end function
235 prexstat
= TNFCTL_ERR_INTERNAL
;
240 prexstat
= decode(hndl
, next
, &nextnames
, &nextaddrs
);
244 /* count number of elements - caution: empty 'for' loop */
245 for (count
= 0; nextnames
[count
]; count
++)
247 count
++; /* since it was 0 based */
249 /* allocate one more for new function name */
250 new_p
->name_ptrs
= malloc((count
+ 1) *
251 sizeof (new_p
->name_ptrs
[0]));
252 if (new_p
->name_ptrs
== NULL
) {
253 prexstat
= TNFCTL_ERR_ALLOCFAIL
;
256 new_p
->func_addrs
= malloc((count
+ 1) *
257 sizeof (new_p
->func_addrs
[0]));
258 if (new_p
->func_addrs
== NULL
) {
259 prexstat
= TNFCTL_ERR_ALLOCFAIL
;
262 name_pp
= new_p
->name_ptrs
;
263 addr_p
= new_p
->func_addrs
;
265 name_pp
[0] = thisname
;
266 for (j
= 0; j
< count
; j
++) {
267 name_pp
[j
+ 1] = nextnames
[j
];
268 addr_p
[j
+ 1] = nextaddrs
[j
];
271 prexstat
= findname(hndl
, addr
, &thisname
);
272 if (prexstat
!= TNFCTL_ERR_USR1
) {
274 * base case - end function is the only function
275 * that can be pointed at directly
277 if (prexstat
== TNFCTL_ERR_NONE
)
278 prexstat
= TNFCTL_ERR_NONE
;
281 new_p
->name_ptrs
= malloc(sizeof (new_p
->name_ptrs
[0]));
282 if (new_p
->name_ptrs
== NULL
) {
283 prexstat
= TNFCTL_ERR_ALLOCFAIL
;
286 new_p
->func_addrs
= malloc(sizeof (new_p
->func_addrs
[0]));
287 if (new_p
->func_addrs
== NULL
) {
288 prexstat
= TNFCTL_ERR_ALLOCFAIL
;
291 new_p
->name_ptrs
[0] = NULL
;
292 new_p
->func_addrs
[0] = NULL
;
295 DBG_TNF_PROBE_1(decode_3
, "libtnfctl",
296 "sunw%verbosity 2; sunw%debug 'decode built'",
297 tnf_string
, func_name
, (thisname
) ? (thisname
) : "end_func");
299 find_pp
= (decode_key_t
**)tsearch(new_p
, &hndl
->decoderoot
,
301 assert(*find_pp
== new_p
);
302 *func_names
= new_p
->name_ptrs
;
303 *func_addrs
= new_p
->func_addrs
;
304 return (TNFCTL_ERR_NONE
);
308 if (new_p
->name_ptrs
)
309 free(new_p
->name_ptrs
);
310 if (new_p
->func_addrs
)
311 free(new_p
->func_addrs
);
319 * iscomb() - determine whether the pointed to function is a combination. If
320 * it is, return the down and next pointers
322 static tnfctl_errcode_t
323 iscomb(tnfctl_handle_t
*hndl
, uintptr_t addr
, uintptr_t *down_p
,
324 uintptr_t *next_p
, boolean_t
*ret_val
)
327 boolean_t matched
= B_FALSE
;
329 for (type
= 0; type
< PRB_COMB_COUNT
; type
++) {
338 int tmp_bits
= prb_callinfo
.mask
;
340 /* allocate room to copy the target code */
341 size
= (size_t)(calltmpl
[type
].end
- calltmpl
[type
].entry
);
342 targ_p
= malloc(size
);
344 return (TNFCTL_ERR_ALLOCFAIL
);
346 /* copy code from target */
347 miscstat
= hndl
->p_read(hndl
->proc_p
, addr
, targ_p
, size
);
350 return (TNFCTL_ERR_INTERNAL
);
353 /* find the number of bits before the highest bit in mask */
354 while (tmp_bits
> 0) {
359 /* loop over all the words */
360 tptr
= (char *)calltmpl
[type
].entry
;
361 for (ptr
= targ_p
; ptr
< (targ_p
+ size
); ptr
++, tptr
++) {
364 /* LINTED pointer cast may result in improper alignment */
365 int *uptr
= (int *)ptr
;
368 * If we are pointing at one of the words that we
369 * patch, * (down or next displ) then read that value
370 * in. * Otherwise make sure the words match.
372 if ((uintptr_t)tptr
== calltmpl
[type
].down
+
373 prb_callinfo
.offset
) {
375 downbits
&= prb_callinfo
.mask
;
377 downbits
= (downbits
<< num_bits
) >> num_bits
;
378 downbits
<<= prb_callinfo
.shift
;
379 downaddr
= addr
+ (ptr
- targ_p
) + downbits
;
382 /* intel is relative to *next* instruction */
387 } else if ((uintptr_t)tptr
== calltmpl
[type
].next
+
388 prb_callinfo
.offset
) {
390 nextbits
&= prb_callinfo
.mask
;
392 nextbits
= (nextbits
<< num_bits
) >> num_bits
;
393 nextbits
<<= prb_callinfo
.shift
;
394 nextaddr
= addr
+ (ptr
- targ_p
) + nextbits
;
397 /* intel is relative to *next* instruction */
403 /* the byte better match or we bail */
409 /* YOWSA! - its a match */
413 /* free allocated memory */
421 return (TNFCTL_ERR_NONE
);
426 return (TNFCTL_ERR_NONE
);
430 #define FUNC_BUF_SIZE 32
432 * findname() - find a name for a function given its address.
434 static tnfctl_errcode_t
435 findname(tnfctl_handle_t
*hndl
, uintptr_t addr
, char **ret_name
)
438 tnfctl_errcode_t prexstat
;
441 prexstat
= _tnfctl_sym_findname(hndl
, addr
, &symname
);
442 if ((prexstat
== TNFCTL_ERR_NONE
) && (symname
!= NULL
)) {
447 * If we find "tnf_trace_end" then we should not report it
448 * as this is the "end-cap" function and should be hidden
449 * from the user. Return a null string instead ...
451 if (strcmp(symname
, TRACE_END_FUNC
) == 0) {
452 return (TNFCTL_ERR_USR1
);
455 return (TNFCTL_ERR_NONE
);
460 buffer
= malloc(FUNC_BUF_SIZE
);
462 return (TNFCTL_ERR_ALLOCFAIL
);
464 /* no name found, use the address */
465 (void) sprintf(buffer
, "func@0x%p", addr
);
467 return (TNFCTL_ERR_NONE
);
473 * find() - try to find an existing combination that satisfies ...
476 find(tnfctl_handle_t
*hndl
, comb_op_t op
, uintptr_t down
, uintptr_t next
,
480 comb_key_t
**find_pp
;
487 find_pp
= (comb_key_t
**)tfind(&key
, &hndl
->buildroot
, comb_compare
);
489 *comb_p
= (*find_pp
)->comb
;
497 * add() - adds a combination to combination cache
499 static tnfctl_errcode_t
500 add(tnfctl_handle_t
*hndl
, comb_op_t op
, uintptr_t down
, uintptr_t next
,
504 /* LINTED set but not used in function */
505 comb_key_t
**ret_pp __unused
;
507 new_p
= malloc(sizeof (comb_key_t
));
509 return (TNFCTL_ERR_ALLOCFAIL
);
516 ret_pp
= (comb_key_t
**)tsearch(new_p
, &hndl
->buildroot
,
518 assert(*ret_pp
== new_p
);
519 return (TNFCTL_ERR_NONE
);
524 * decode_compare() - comparison function used for tree search for
528 decode_compare(const void *v0p
, const void *v1p
)
530 const decode_key_t
*k0p
= v0p
;
531 const decode_key_t
*k1p
= v1p
;
533 return (int)((uintptr_t)k1p
->addr
- (uintptr_t)k0p
->addr
);
534 } /* end decode_compare */
538 * comb_compare() - comparison function used for tree search for combinations
541 comb_compare(const void *v0p
, const void *v1p
)
543 const comb_key_t
*k0p
= v0p
;
544 const comb_key_t
*k1p
= v1p
;
546 if (k0p
->op
!= k1p
->op
)
547 return ((k0p
->op
< k1p
->op
) ? -1 : 1);
549 if (k0p
->down
!= k1p
->down
)
550 return ((k0p
->down
< k1p
->down
) ? -1 : 1);
552 if (k0p
->next
!= k1p
->next
)
553 return ((k0p
->next
< k1p
->next
) ? -1 : 1);
557 } /* end comb_compare */
560 * build() - build a composition
562 static tnfctl_errcode_t
563 build(tnfctl_handle_t
*hndl
, comb_op_t op
, uintptr_t down
, uintptr_t next
,
568 char *buffer_p
= NULL
;
573 tnfctl_errcode_t prexstat
;
576 size
= calltmpl
[op
].end
- calltmpl
[op
].entry
;
578 /* allocate memory in the target process */
579 prexstat
= _tnfctl_targmem_alloc(hndl
, size
, &addr
);
581 DBG((void) fprintf(stderr
,
582 "build: trouble allocating target memory:\n"));
586 /* allocate a scratch buffer, copy the template into it */
587 buffer_p
= malloc(size
);
589 DBG((void) fprintf(stderr
, "build: alloc failed\n"));
590 prexstat
= TNFCTL_ERR_ALLOCFAIL
;
593 (void) memcpy(buffer_p
, (void *) calltmpl
[op
].entry
, size
);
595 /* poke the down address */
596 offset
= calltmpl
[op
].down
- calltmpl
[op
].entry
;
597 /*LINTED pointer cast may result in improper alignment*/
598 word_p
= (unsigned *)(buffer_p
+ offset
+ prb_callinfo
.offset
);
599 contents
= down
- (addr
+ offset
);
601 contents
-= 5; /* intel offset is relative to *next* instr */
604 DBG_TNF_PROBE_4(build_1
, "libtnfctl", "sunw%verbosity 3",
605 tnf_opaque
, down
, down
, tnf_opaque
, contents
, contents
,
606 tnf_opaque
, word_p
, word_p
, tnf_long
, offset
, offset
);
608 *word_p
&= ~prb_callinfo
.mask
; /* clear the relevant field */
609 *word_p
|= ((contents
>> prb_callinfo
.shift
) & prb_callinfo
.mask
);
611 /* poke the next address */
612 offset
= calltmpl
[op
].next
- calltmpl
[op
].entry
;
613 /*LINTED pointer cast may result in improper alignment*/
614 word_p
= (unsigned *)(buffer_p
+ offset
+ prb_callinfo
.offset
);
615 contents
= next
- (addr
+ offset
);
617 contents
-= 5; /* intel offset is relative to *next* instr */
620 DBG_TNF_PROBE_4(build_2
, "libtnfctl", "sunw%verbosity 3",
621 tnf_opaque
, next
, next
, tnf_opaque
, contents
, contents
,
622 tnf_opaque
, word_p
, word_p
, tnf_long
, offset
, offset
);
624 *word_p
&= ~prb_callinfo
.mask
; /* clear the relevant field */
625 *word_p
|= ((contents
>> prb_callinfo
.shift
) & prb_callinfo
.mask
);
627 /* copy the combination template into target memory */
628 miscstat
= hndl
->p_write(hndl
->proc_p
, addr
, buffer_p
, size
);
630 DBG((void) fprintf(stderr
,
631 "build: trouble writing combination: \n"));
632 prexstat
= TNFCTL_ERR_INTERNAL
;
636 prexstat
= add(hndl
, op
, down
, next
, addr
);