8854 libm: variable set but not used
[unleashed.git] / usr / src / lib / libtnfctl / comb.c
blob447745d4d75d20e5ef2e36a10f4f69de7c778faa
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
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.
31 #ifndef DEBUG
32 #define NDEBUG 1
33 #endif
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <search.h>
39 #include <assert.h>
40 #include <sys/types.h>
42 #include "tnfctl_int.h"
43 #include "dbg.h"
47 * Typedefs
50 typedef struct comb_callinfo {
51 unsigned offset;
52 unsigned shift; /* shift right <n> bits */
53 unsigned mask;
55 } comb_callinfo_t;
57 typedef struct comb_calltmpl {
58 uintptr_t entry;
59 uintptr_t down;
60 uintptr_t next;
61 uintptr_t end;
63 } comb_calltmpl_t;
65 typedef struct comb_key {
66 comb_op_t op;
67 uintptr_t down;
68 uintptr_t next;
69 uintptr_t comb;
70 } comb_key_t;
72 typedef struct decode_key {
73 uintptr_t addr;
74 char **name_ptrs;
75 uintptr_t *func_addrs;
76 } decode_key_t;
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}
98 * Declarations
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,
114 char **ret_name);
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.
125 tnfctl_errcode_t
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;
131 *comb_p = NULL;
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);
150 return (prexstat);
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
157 * by the client.
159 tnfctl_errcode_t
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");
173 return (prexstat);
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;
190 decode_key_t key;
191 decode_key_t *new_p = NULL;
192 decode_key_t **find_pp;
193 uintptr_t down;
194 uintptr_t next;
195 char *thisname = NULL;
196 boolean_t is_combination;
198 /* see if we can find the previously decoded answer */
199 key.addr = addr;
200 find_pp = (decode_key_t **)tfind(&key, &hndl->decoderoot,
201 decode_compare);
202 if (find_pp) {
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));
211 if (!new_p)
212 return (TNFCTL_ERR_ALLOCFAIL);
213 new_p->addr = addr;
215 prexstat = iscomb(hndl, addr, &down, &next, &is_combination);
216 if (prexstat)
217 goto Error;
219 if (is_combination) {
220 char **nextnames;
221 uintptr_t *nextaddrs;
222 char **name_pp;
223 uintptr_t *addr_p;
224 int count, j;
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;
236 goto Error;
237 } else if (prexstat)
238 goto Error;
240 prexstat = decode(hndl, next, &nextnames, &nextaddrs);
241 if (prexstat)
242 goto Error;
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;
254 goto Error;
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;
260 goto Error;
262 name_pp = new_p->name_ptrs;
263 addr_p = new_p->func_addrs;
264 addr_p[0] = down;
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];
270 } else {
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;
279 goto Error;
281 new_p->name_ptrs = malloc(sizeof (new_p->name_ptrs[0]));
282 if (new_p->name_ptrs == NULL) {
283 prexstat = TNFCTL_ERR_ALLOCFAIL;
284 goto Error;
286 new_p->func_addrs = malloc(sizeof (new_p->func_addrs[0]));
287 if (new_p->func_addrs == NULL) {
288 prexstat = TNFCTL_ERR_ALLOCFAIL;
289 goto Error;
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,
300 decode_compare);
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);
306 Error:
307 if (new_p) {
308 if (new_p->name_ptrs)
309 free(new_p->name_ptrs);
310 if (new_p->func_addrs)
311 free(new_p->func_addrs);
312 free(new_p);
314 return (prexstat);
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)
326 int type;
327 boolean_t matched = B_FALSE;
329 for (type = 0; type < PRB_COMB_COUNT; type++) {
330 size_t size;
331 int miscstat;
332 char *targ_p;
333 char *ptr;
334 char *tptr;
335 uintptr_t downaddr;
336 uintptr_t nextaddr;
337 int num_bits = 0;
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);
343 if (!targ_p)
344 return (TNFCTL_ERR_ALLOCFAIL);
346 /* copy code from target */
347 miscstat = hndl->p_read(hndl->proc_p, addr, targ_p, size);
348 if (miscstat) {
349 free(targ_p);
350 return (TNFCTL_ERR_INTERNAL);
353 /* find the number of bits before the highest bit in mask */
354 while (tmp_bits > 0) {
355 num_bits++;
356 tmp_bits <<= 1;
359 /* loop over all the words */
360 tptr = (char *)calltmpl[type].entry;
361 for (ptr = targ_p; ptr < (targ_p + size); ptr++, tptr++) {
362 int downbits;
363 int nextbits;
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) {
374 downbits = *uptr;
375 downbits &= prb_callinfo.mask;
376 /* sign extend */
377 downbits = (downbits << num_bits) >> num_bits;
378 downbits <<= prb_callinfo.shift;
379 downaddr = addr + (ptr - targ_p) + downbits;
380 #if defined(i386)
381 downaddr += 4;
382 /* intel is relative to *next* instruction */
383 #endif
385 ptr += 3;
386 tptr += 3;
387 } else if ((uintptr_t)tptr == calltmpl[type].next +
388 prb_callinfo.offset) {
389 nextbits = *uptr;
390 nextbits &= prb_callinfo.mask;
391 /* sign extend */
392 nextbits = (nextbits << num_bits) >> num_bits;
393 nextbits <<= prb_callinfo.shift;
394 nextaddr = addr + (ptr - targ_p) + nextbits;
395 #if defined(i386)
396 nextaddr += 4;
397 /* intel is relative to *next* instruction */
398 #endif
400 ptr += 3;
401 tptr += 3;
402 } else {
403 /* the byte better match or we bail */
404 if (*ptr != *tptr)
405 goto NextComb;
409 /* YOWSA! - its a match */
410 matched = B_TRUE;
412 NextComb:
413 /* free allocated memory */
414 if (targ_p)
415 free(targ_p);
417 if (matched) {
418 *down_p = downaddr;
419 *next_p = nextaddr;
420 *ret_val = B_TRUE;
421 return (TNFCTL_ERR_NONE);
425 *ret_val = B_FALSE;
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)
437 char *symname;
438 tnfctl_errcode_t prexstat;
440 symname = NULL;
441 prexstat = _tnfctl_sym_findname(hndl, addr, &symname);
442 if ((prexstat == TNFCTL_ERR_NONE) && (symname != NULL)) {
443 /* found a name */
446 * SPECIAL CASE
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);
453 } else {
454 *ret_name = symname;
455 return (TNFCTL_ERR_NONE);
457 } else {
458 char *buffer;
460 buffer = malloc(FUNC_BUF_SIZE);
461 if (buffer == NULL)
462 return (TNFCTL_ERR_ALLOCFAIL);
464 /* no name found, use the address */
465 (void) sprintf(buffer, "func@0x%p", addr);
466 *ret_name = buffer;
467 return (TNFCTL_ERR_NONE);
473 * find() - try to find an existing combination that satisfies ...
475 static boolean_t
476 find(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down, uintptr_t next,
477 uintptr_t *comb_p)
479 comb_key_t key;
480 comb_key_t **find_pp;
482 key.op = op;
483 key.down = down;
484 key.next = next;
485 key.comb = NULL;
487 find_pp = (comb_key_t **)tfind(&key, &hndl->buildroot, comb_compare);
488 if (find_pp) {
489 *comb_p = (*find_pp)->comb;
490 return (B_TRUE);
491 } else
492 return (B_FALSE);
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,
501 uintptr_t comb)
503 comb_key_t *new_p;
504 /* LINTED set but not used in function */
505 comb_key_t **ret_pp __unused;
507 new_p = malloc(sizeof (comb_key_t));
508 if (!new_p)
509 return (TNFCTL_ERR_ALLOCFAIL);
511 new_p->op = op;
512 new_p->down = down;
513 new_p->next = next;
514 new_p->comb = comb;
516 ret_pp = (comb_key_t **)tsearch(new_p, &hndl->buildroot,
517 comb_compare);
518 assert(*ret_pp == new_p);
519 return (TNFCTL_ERR_NONE);
524 * decode_compare() - comparison function used for tree search for
525 * combinations
527 static int
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
540 static int
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);
555 return (0);
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,
564 uintptr_t *comb_p)
566 size_t size;
567 uintptr_t addr;
568 char *buffer_p = NULL;
569 uintptr_t offset;
570 uintptr_t contents;
571 unsigned *word_p;
572 int miscstat;
573 tnfctl_errcode_t prexstat;
575 *comb_p = NULL;
576 size = calltmpl[op].end - calltmpl[op].entry;
578 /* allocate memory in the target process */
579 prexstat = _tnfctl_targmem_alloc(hndl, size, &addr);
580 if (prexstat) {
581 DBG((void) fprintf(stderr,
582 "build: trouble allocating target memory:\n"));
583 goto Error;
586 /* allocate a scratch buffer, copy the template into it */
587 buffer_p = malloc(size);
588 if (!buffer_p) {
589 DBG((void) fprintf(stderr, "build: alloc failed\n"));
590 prexstat = TNFCTL_ERR_ALLOCFAIL;
591 goto Error;
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);
600 #if defined(i386)
601 contents -= 5; /* intel offset is relative to *next* instr */
602 #endif
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);
616 #if defined(i386)
617 contents -= 5; /* intel offset is relative to *next* instr */
618 #endif
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);
629 if (miscstat) {
630 DBG((void) fprintf(stderr,
631 "build: trouble writing combination: \n"));
632 prexstat = TNFCTL_ERR_INTERNAL;
633 goto Error;
635 *comb_p = addr;
636 prexstat = add(hndl, op, down, next, addr);
638 Error:
639 if (buffer_p)
640 free(buffer_p);
641 return (prexstat);