1 /* 2 * CDDL HEADER START 3 * 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. 8 * 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. 13 * 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] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1994, by Sun Microsytems, Inc. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Functions that know how to create and decode combinations that are 30 * used for connecting probe functions. 31 */ 32 33 #ifndef DEBUG 34 #define NDEBUG 1 35 #endif 36 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> 43 44 #include "tnfctl_int.h" 45 #include "dbg.h" 46 47 48 /* 49 * Typedefs 50 */ 51 52 typedef struct comb_callinfo { 53 unsigned offset; 54 unsigned shift; /* shift right <n> bits */ 55 unsigned mask; 56 57 } comb_callinfo_t; 58 59 typedef struct comb_calltmpl { 60 uintptr_t entry; 61 uintptr_t down; 62 uintptr_t next; 63 uintptr_t end; 64 65 } comb_calltmpl_t; 66 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; 73 74 typedef struct decode_key { 75 uintptr_t addr; 76 char **name_ptrs; 77 uintptr_t *func_addrs; 78 } decode_key_t; 79 80 81 /* 82 * Global - defined in assembler file 83 */ 84 extern comb_callinfo_t prb_callinfo; 85 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); 90 91 static comb_calltmpl_t calltmpl[PRB_COMB_COUNT] = { 92 { 93 (uintptr_t) prb_chain_entry, 94 (uintptr_t) prb_chain_down, 95 (uintptr_t) prb_chain_next, 96 (uintptr_t) prb_chain_end} 97 }; 98 99 /* 100 * Declarations 101 */ 102 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); 117 118 119 /* ---------------------------------------------------------------- */ 120 /* ----------------------- Public Functions ----------------------- */ 121 /* ---------------------------------------------------------------- */ 122 123 /* 124 * _tnfctl_comb_build() - finds (or builds) a combination satisfing the op, 125 * down and next constraints of the caller. 126 */ 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) 130 { 131 tnfctl_errcode_t prexstat; 132 133 *comb_p = NULL; 134 135 DBG_TNF_PROBE_0(_tnfctl_comb_build_start, "libtnfctl", 136 "start _tnfctl_comb_build; sunw%verbosity 1"); 137 138 if (find(hndl, op, down, next, comb_p)) { 139 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); 143 144 return (TNFCTL_ERR_NONE); 145 } 146 prexstat = build(hndl, op, down, next, comb_p); 147 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); 151 152 return (prexstat); 153 } 154 155 156 /* 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. 160 */ 161 tnfctl_errcode_t 162 _tnfctl_comb_decode(tnfctl_handle_t *hndl, uintptr_t addr, char ***func_names, 163 uintptr_t **func_addrs) 164 { 165 tnfctl_errcode_t prexstat; 166 167 DBG_TNF_PROBE_0(_tnfctl_comb_decode_start, "libtnfctl", 168 "start _tnfctl_comb_decode; sunw%verbosity 2"); 169 170 prexstat = decode(hndl, addr, func_names, func_addrs); 171 172 DBG_TNF_PROBE_0(_tnfctl_comb_decode_end, "libtnfctl", 173 "end _tnfctl_comb_decode; sunw%verbosity 2"); 174 175 return (prexstat); 176 } 177 178 179 /* ---------------------------------------------------------------- */ 180 /* ----------------------- Private Functions ---------------------- */ 181 /* ---------------------------------------------------------------- */ 182 183 /* 184 * if combination has been decoded, return decoded info., else 185 * decode combination and cache information 186 */ 187 static tnfctl_errcode_t 188 decode(tnfctl_handle_t *hndl, uintptr_t addr, char ***func_names, 189 uintptr_t **func_addrs) 190 { 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; 199 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); 210 } 211 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; 216 217 prexstat = iscomb(hndl, addr, &down, &next, &is_combination); 218 if (prexstat) 219 goto Error; 220 221 if (is_combination) { 222 char **nextnames; 223 uintptr_t *nextaddrs; 224 char **name_pp; 225 uintptr_t *addr_p; 226 int count, j; 227 228 DBG_TNF_PROBE_2(decode_2, "libtnfctl", "sunw%verbosity 2;", 229 tnf_opaque, down, down, 230 tnf_opaque, next, next); 231 232 prexstat = findname(hndl, down, &thisname); 233 if (prexstat == TNFCTL_ERR_USR1) { 234 /* 235 * should never happen - combination should not 236 * point at the end function 237 */ 238 prexstat = TNFCTL_ERR_INTERNAL; 239 goto Error; 240 } else if (prexstat) 241 goto Error; 242 243 prexstat = decode(hndl, next, &nextnames, &nextaddrs); 244 if (prexstat) 245 goto Error; 246 247 /* count number of elements - caution: empty 'for' loop */ 248 for (count = 0; nextnames[count]; count++); 249 count++; /* since it was 0 based */ 250 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; 257 } 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; 263 } 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]; 271 } 272 } else { 273 prexstat = findname(hndl, addr, &thisname); 274 if (prexstat != TNFCTL_ERR_USR1) { 275 /* 276 * base case - end function is the only function 277 * that can be pointed at directly 278 */ 279 if (prexstat == TNFCTL_ERR_NONE) 280 prexstat = TNFCTL_ERR_NONE; 281 goto Error; 282 } 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; 287 } 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; 292 } 293 new_p->name_ptrs[0] = NULL; 294 new_p->func_addrs[0] = NULL; 295 } 296 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"); 301 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); 308 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); 316 } 317 return (prexstat); 318 } 319 320 321 /* 322 * iscomb() - determine whether the pointed to function is a combination. If 323 * it is, return the down and next pointers 324 */ 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) 329 { 330 int type; 331 boolean_t matched = B_FALSE; 332 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; 343 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); 349 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); 355 } 356 357 /* find the number of bits before the highest bit in mask */ 358 while (tmp_bits > 0) { 359 num_bits++; 360 tmp_bits <<= 1; 361 } 362 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; 370 371 /* 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. 375 */ 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 388 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 403 404 ptr += 3; 405 tptr += 3; 406 } else { 407 /* the byte better match or we bail */ 408 if (*ptr != *tptr) 409 goto NextComb; 410 } 411 } 412 413 /* YOWSA! - its a match */ 414 matched = B_TRUE; 415 416 NextComb: 417 /* free allocated memory */ 418 if (targ_p) 419 free(targ_p); 420 421 if (matched) { 422 *down_p = downaddr; 423 *next_p = nextaddr; 424 *ret_val = B_TRUE; 425 return (TNFCTL_ERR_NONE); 426 } 427 } 428 429 *ret_val = B_FALSE; 430 return (TNFCTL_ERR_NONE); 431 } 432 433 434 #define FUNC_BUF_SIZE 32 435 /* 436 * findname() - find a name for a function given its address. 437 */ 438 static tnfctl_errcode_t 439 findname(tnfctl_handle_t *hndl, uintptr_t addr, char **ret_name) 440 { 441 char *symname; 442 tnfctl_errcode_t prexstat; 443 444 symname = NULL; 445 prexstat = _tnfctl_sym_findname(hndl, addr, &symname); 446 if ((prexstat == TNFCTL_ERR_NONE) && (symname != NULL)) { 447 /* found a name */ 448 449 /* 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 ... 454 */ 455 if (strcmp(symname, TRACE_END_FUNC) == 0) { 456 return (TNFCTL_ERR_USR1); 457 } else { 458 *ret_name = symname; 459 return (TNFCTL_ERR_NONE); 460 } 461 } else { 462 char *buffer; 463 464 buffer = malloc(FUNC_BUF_SIZE); 465 if (buffer == NULL) 466 return (TNFCTL_ERR_ALLOCFAIL); 467 468 /* no name found, use the address */ 469 (void) sprintf(buffer, "func@0x%p", addr); 470 *ret_name = buffer; 471 return (TNFCTL_ERR_NONE); 472 } 473 } 474 475 476 /* 477 * find() - try to find an existing combination that satisfies ... 478 */ 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) 482 { 483 comb_key_t key; 484 comb_key_t **find_pp; 485 486 key.op = op; 487 key.down = down; 488 key.next = next; 489 key.comb = NULL; 490 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); 497 } 498 499 500 /* 501 * add() - adds a combination to combination cache 502 */ 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) 506 { 507 comb_key_t *new_p; 508 /* LINTED set but not used in function */ 509 comb_key_t **ret_pp; 510 511 new_p = (comb_key_t *) malloc(sizeof (comb_key_t)); 512 if (!new_p) 513 return (TNFCTL_ERR_ALLOCFAIL); 514 515 new_p->op = op; 516 new_p->down = down; 517 new_p->next = next; 518 new_p->comb = comb; 519 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); 524 } 525 526 527 /* 528 * decode_compare() - comparison function used for tree search for 529 * combinations 530 */ 531 static int 532 decode_compare(const void *v0p, const void *v1p) 533 { 534 decode_key_t *k0p = (decode_key_t *) v0p; 535 decode_key_t *k1p = (decode_key_t *) v1p; 536 537 return (int) ((uintptr_t) k1p->addr - (uintptr_t) k0p->addr); 538 } /* end decode_compare */ 539 540 541 /* 542 * comb_compare() - comparison function used for tree search for combinations 543 */ 544 static int 545 comb_compare(const void *v0p, const void *v1p) 546 { 547 comb_key_t *k0p = (comb_key_t *) v0p; 548 comb_key_t *k1p = (comb_key_t *) v1p; 549 550 if (k0p->op != k1p->op) 551 return ((k0p->op < k1p->op) ? -1 : 1); 552 553 if (k0p->down != k1p->down) 554 return ((k0p->down < k1p->down) ? -1 : 1); 555 556 if (k0p->next != k1p->next) 557 return ((k0p->next < k1p->next) ? -1 : 1); 558 559 return (0); 560 561 } /* end comb_compare */ 562 563 /* 564 * build() - build a composition 565 */ 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) 569 { 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; 578 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 586 587 *comb_p = NULL; 588 size = calltmpl[op].end - calltmpl[op].entry; 589 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; 596 } 597 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; 604 } 605 (void) memcpy(buffer_p, (void *) calltmpl[op].entry, size); 606 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 615 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); 621 622 *word_p &= ~prb_callinfo.mask; /* clear the relevant field */ 623 *word_p |= ((contents >> prb_callinfo.shift) & prb_callinfo.mask); 624 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 633 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); 639 640 *word_p &= ~prb_callinfo.mask; /* clear the relevant field */ 641 *word_p |= ((contents >> prb_callinfo.shift) & prb_callinfo.mask); 642 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; 650 } 651 *comb_p = addr; 652 prexstat = add(hndl, op, down, next, addr); 653 654 Error: 655 if (buffer_p) 656 free(buffer_p); 657 return (prexstat); 658 } 659