8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libtnfctl / comb.c
bloba67863e4f294134c0a6f7aac1db117230f45ec6e
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.
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.
33 #ifndef DEBUG
34 #define NDEBUG 1
35 #endif
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <search.h>
41 #include <assert.h>
42 #include <sys/types.h>
44 #include "tnfctl_int.h"
45 #include "dbg.h"
49 * Typedefs
52 typedef struct comb_callinfo {
53 unsigned offset;
54 unsigned shift; /* shift right <n> bits */
55 unsigned mask;
57 } comb_callinfo_t;
59 typedef struct comb_calltmpl {
60 uintptr_t entry;
61 uintptr_t down;
62 uintptr_t next;
63 uintptr_t end;
65 } comb_calltmpl_t;
67 typedef struct comb_key {
68 comb_op_t op;
69 uintptr_t down;
70 uintptr_t next;
71 uintptr_t comb;
72 } comb_key_t;
74 typedef struct decode_key {
75 uintptr_t addr;
76 char **name_ptrs;
77 uintptr_t *func_addrs;
78 } decode_key_t;
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}
100 * Declarations
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,
116 char **ret_name);
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.
127 tnfctl_errcode_t
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;
133 *comb_p = NULL;
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);
152 return (prexstat);
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
159 * by the client.
161 tnfctl_errcode_t
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");
175 return (prexstat);
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;
192 decode_key_t key;
193 decode_key_t *new_p = NULL;
194 decode_key_t **find_pp;
195 uintptr_t down;
196 uintptr_t next;
197 char *thisname = NULL;
198 boolean_t is_combination;
200 /* see if we can find the previously decoded answer */
201 key.addr = addr;
202 find_pp = (decode_key_t **) tfind(&key, &hndl->decoderoot,
203 decode_compare);
204 if (find_pp) {
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));
213 if (!new_p)
214 return (TNFCTL_ERR_ALLOCFAIL);
215 new_p->addr = addr;
217 prexstat = iscomb(hndl, addr, &down, &next, &is_combination);
218 if (prexstat)
219 goto Error;
221 if (is_combination) {
222 char **nextnames;
223 uintptr_t *nextaddrs;
224 char **name_pp;
225 uintptr_t *addr_p;
226 int count, j;
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;
239 goto Error;
240 } else if (prexstat)
241 goto Error;
243 prexstat = decode(hndl, next, &nextnames, &nextaddrs);
244 if (prexstat)
245 goto Error;
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;
256 goto Error;
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;
262 goto Error;
264 name_pp = new_p->name_ptrs;
265 addr_p = new_p->func_addrs;
266 addr_p[0] = down;
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];
272 } else {
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;
281 goto Error;
283 new_p->name_ptrs = malloc(sizeof (new_p->name_ptrs[0]));
284 if (new_p->name_ptrs == NULL) {
285 prexstat = TNFCTL_ERR_ALLOCFAIL;
286 goto Error;
288 new_p->func_addrs = malloc(sizeof (new_p->func_addrs[0]));
289 if (new_p->func_addrs == NULL) {
290 prexstat = TNFCTL_ERR_ALLOCFAIL;
291 goto Error;
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);
309 Error:
310 if (new_p) {
311 if (new_p->name_ptrs)
312 free(new_p->name_ptrs);
313 if (new_p->func_addrs)
314 free(new_p->func_addrs);
315 free(new_p);
317 return (prexstat);
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,
328 boolean_t *ret_val)
330 int type;
331 boolean_t matched = B_FALSE;
333 for (type = 0; type < PRB_COMB_COUNT; type++) {
334 size_t size;
335 int miscstat;
336 char *targ_p;
337 char *ptr;
338 char *tptr;
339 uintptr_t downaddr;
340 uintptr_t nextaddr;
341 int num_bits = 0;
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);
347 if (!targ_p)
348 return (TNFCTL_ERR_ALLOCFAIL);
350 /* copy code from target */
351 miscstat = hndl->p_read(hndl->proc_p, addr, targ_p, size);
352 if (miscstat) {
353 free(targ_p);
354 return (TNFCTL_ERR_INTERNAL);
357 /* find the number of bits before the highest bit in mask */
358 while (tmp_bits > 0) {
359 num_bits++;
360 tmp_bits <<= 1;
363 /* loop over all the words */
364 tptr = (char *) calltmpl[type].entry;
365 for (ptr = targ_p; ptr < (targ_p + size); ptr++, tptr++) {
366 int downbits;
367 int nextbits;
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) {
378 downbits = *uptr;
379 downbits &= prb_callinfo.mask;
380 /* sign extend */
381 downbits = (downbits << num_bits) >> num_bits;
382 downbits <<= prb_callinfo.shift;
383 downaddr = addr + (ptr - targ_p) + downbits;
384 #if defined(i386)
385 downaddr += 4;
386 /* intel is relative to *next* instruction */
387 #endif
389 ptr += 3;
390 tptr += 3;
391 } else if ((uintptr_t) tptr == calltmpl[type].next +
392 prb_callinfo.offset) {
393 nextbits = *uptr;
394 nextbits &= prb_callinfo.mask;
395 /* sign extend */
396 nextbits = (nextbits << num_bits) >> num_bits;
397 nextbits <<= prb_callinfo.shift;
398 nextaddr = addr + (ptr - targ_p) + nextbits;
399 #if defined(i386)
400 nextaddr += 4;
401 /* intel is relative to *next* instruction */
402 #endif
404 ptr += 3;
405 tptr += 3;
406 } else {
407 /* the byte better match or we bail */
408 if (*ptr != *tptr)
409 goto NextComb;
413 /* YOWSA! - its a match */
414 matched = B_TRUE;
416 NextComb:
417 /* free allocated memory */
418 if (targ_p)
419 free(targ_p);
421 if (matched) {
422 *down_p = downaddr;
423 *next_p = nextaddr;
424 *ret_val = B_TRUE;
425 return (TNFCTL_ERR_NONE);
429 *ret_val = B_FALSE;
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)
441 char *symname;
442 tnfctl_errcode_t prexstat;
444 symname = NULL;
445 prexstat = _tnfctl_sym_findname(hndl, addr, &symname);
446 if ((prexstat == TNFCTL_ERR_NONE) && (symname != NULL)) {
447 /* found a name */
450 * SPECIAL CASE
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);
457 } else {
458 *ret_name = symname;
459 return (TNFCTL_ERR_NONE);
461 } else {
462 char *buffer;
464 buffer = malloc(FUNC_BUF_SIZE);
465 if (buffer == NULL)
466 return (TNFCTL_ERR_ALLOCFAIL);
468 /* no name found, use the address */
469 (void) sprintf(buffer, "func@0x%p", addr);
470 *ret_name = buffer;
471 return (TNFCTL_ERR_NONE);
477 * find() - try to find an existing combination that satisfies ...
479 static boolean_t
480 find(tnfctl_handle_t *hndl, comb_op_t op, uintptr_t down, uintptr_t next,
481 uintptr_t * comb_p)
483 comb_key_t key;
484 comb_key_t **find_pp;
486 key.op = op;
487 key.down = down;
488 key.next = next;
489 key.comb = NULL;
491 find_pp = (comb_key_t **) tfind(&key, &hndl->buildroot, comb_compare);
492 if (find_pp) {
493 *comb_p = (*find_pp)->comb;
494 return (B_TRUE);
495 } else
496 return (B_FALSE);
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,
505 uintptr_t comb)
507 comb_key_t *new_p;
508 /* LINTED set but not used in function */
509 comb_key_t **ret_pp;
511 new_p = (comb_key_t *) malloc(sizeof (comb_key_t));
512 if (!new_p)
513 return (TNFCTL_ERR_ALLOCFAIL);
515 new_p->op = op;
516 new_p->down = down;
517 new_p->next = next;
518 new_p->comb = comb;
520 ret_pp = (comb_key_t **) tsearch(new_p, &hndl->buildroot,
521 comb_compare);
522 assert(*ret_pp == new_p);
523 return (TNFCTL_ERR_NONE);
528 * decode_compare() - comparison function used for tree search for
529 * combinations
531 static int
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
544 static int
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);
559 return (0);
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,
568 uintptr_t *comb_p)
570 size_t size;
571 uintptr_t addr;
572 char *buffer_p = NULL;
573 uintptr_t offset;
574 uintptr_t contents;
575 unsigned *word_p;
576 int miscstat;
577 tnfctl_errcode_t prexstat;
579 #if 0
580 (void) fprintf(stderr, "off=0x%x shift=0x%x mask=0x%x size=%d\n",
581 prb_callinfo.offset,
582 prb_callinfo.shift,
583 prb_callinfo.mask,
584 calltmpl[op].end - calltmpl[op].entry);
585 #endif
587 *comb_p = NULL;
588 size = calltmpl[op].end - calltmpl[op].entry;
590 /* allocate memory in the target process */
591 prexstat = _tnfctl_targmem_alloc(hndl, size, &addr);
592 if (prexstat) {
593 DBG((void) fprintf(stderr,
594 "build: trouble allocating target memory:\n"));
595 goto Error;
598 /* allocate a scratch buffer, copy the template into it */
599 buffer_p = malloc(size);
600 if (!buffer_p) {
601 DBG((void) fprintf(stderr, "build: alloc failed\n"));
602 prexstat = TNFCTL_ERR_ALLOCFAIL;
603 goto Error;
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);
612 #if defined(i386)
613 contents -= 5; /* intel offset is relative to *next* instr */
614 #endif
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);
630 #if defined(i386)
631 contents -= 5; /* intel offset is relative to *next* instr */
632 #endif
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);
645 if (miscstat) {
646 DBG((void) fprintf(stderr,
647 "build: trouble writing combination: \n"));
648 prexstat = TNFCTL_ERR_INTERNAL;
649 goto Error;
651 *comb_p = addr;
652 prexstat = add(hndl, op, down, next, addr);
654 Error:
655 if (buffer_p)
656 free(buffer_p);
657 return (prexstat);