1/* 2 * Copyright (c) 2006-2008 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24// This must be done *after* any references to Foundation.h! 25#define uint_t __Solaris_uint_t 26 27#ifdef __cplusplus 28extern "C" { 29#endif 30 31#include <dt_impl.h> 32#include <dt_provider.h> 33#include <dt_string.h> 34#include <dt_program.h> 35#include "dt_dof_byteswap.h" 36#include "dt_ld.h" 37 38#ifdef __cplusplus 39} 40#endif 41 42#include <mach/machine.h> 43 44#include "arch.h" 45 46#include <stdlib.h> 47#include <errno.h> 48#include <mach/vm_param.h> 49 50#include <string> 51#include <vector> 52#include <sstream> 53#include <unordered_set> 54#include <unordered_map> 55#include <memory> 56 57#define dtrace_separator "$" 58#define dtrace_separator_char '$' 59 60// Why an encoding & decoding prefix? During compilation, the prefix may change... 61#define dtrace_stability_encoding_prefix "___dtrace_stability" 62#define dtrace_stability_decoding_prefix "___dtrace_stability" 63#define dtrace_stability_version "v1" 64 65#define dtrace_typedefs_encoding_prefix "___dtrace_typedefs" 66#define dtrace_typedefs_decoding_prefix "___dtrace_typedefs" 67#define dtrace_typedefs_version "v2" 68 69#define dtrace_probe_encoding_prefix "__dtrace_probe" 70#define dtrace_probe_decoding_prefix "___dtrace_probe" 71#define dtrace_probe_version "v1" 72 73#define dtrace_isenabled_encoding_prefix "__dtrace_isenabled" 74#define dtrace_isenabled_decoding_prefix "___dtrace_isenabled" 75#define dtrace_isenabled_version "v1" 76 77static std::string dt_ld_encode_string(const char* string) 78{ 79 size_t input_length = strlen(string); 80 std::shared_ptr<char> results((char*)malloc(input_length * 2 + 1), &::free); 81 for (int i = 0; i < input_length; i++) { 82 sprintf(&results.get()[i*2],"%02x", (unsigned int)string[i]); 83 } 84 results.get()[input_length*2] = 0; 85 86 return std::string(results.get()); 87} 88 89static std::string dt_ld_decode_string(const char* string) 90{ 91 size_t input_length = strlen(string) / 2; 92 std::shared_ptr<char> results((char*)malloc(input_length * 2 + 1), &::free); 93 for (int i = 0; i < input_length; i++) { 94 unsigned int value; 95 sscanf(&string[i*2],"%2x", &value); 96 results.get()[i] = (unsigned char)value; 97 } 98 results.get()[input_length] = 0; 99 100 return std::string(results.get()); 101} 102 103#pragma mark - 104#pragma mark stability encoding / decoding 105 106char* dt_ld_encode_stability(char* provider_name, dt_provider_t *provider) 107{ 108 // Stability info is encoded as (dtrace_stability_encoding_prefix)(providerName)(dtrace_stability_version)(stability_data) 109 size_t bufsize = sizeof(dtrace_stability_encoding_prefix) + 110 sizeof(dtrace_separator) + 111 sizeof(dtrace_stability_version) + 112 sizeof(dtrace_separator) + 113 strlen(provider_name) + 114 sizeof(dtrace_separator) + 115 sizeof(dtrace_pattr_t) * 3 + // Each attr is 1 byte * an encoding size of 3 bytes. 116 1; // NULL terminator 117 118 char* buffer = (char*)malloc(bufsize); 119 120 snprintf(buffer, bufsize, "%s%s%s%s%s%s%x_%x_%x_%x_%x_%x_%x_%x_%x_%x_%x_%x_%x_%x_%x", 121 dtrace_stability_encoding_prefix, 122 dtrace_separator, 123 provider_name, 124 dtrace_separator, 125 dtrace_stability_version, 126 dtrace_separator, 127 /* provider attributes */ 128 provider->pv_desc.dtvd_attr.dtpa_provider.dtat_name, 129 provider->pv_desc.dtvd_attr.dtpa_provider.dtat_data, 130 provider->pv_desc.dtvd_attr.dtpa_provider.dtat_class, 131 /* module attributes */ 132 provider->pv_desc.dtvd_attr.dtpa_mod.dtat_name, 133 provider->pv_desc.dtvd_attr.dtpa_mod.dtat_data, 134 provider->pv_desc.dtvd_attr.dtpa_mod.dtat_class, 135 /* function attributes */ 136 provider->pv_desc.dtvd_attr.dtpa_func.dtat_name, 137 provider->pv_desc.dtvd_attr.dtpa_func.dtat_data, 138 provider->pv_desc.dtvd_attr.dtpa_func.dtat_class, 139 /* name attributes */ 140 provider->pv_desc.dtvd_attr.dtpa_name.dtat_name, 141 provider->pv_desc.dtvd_attr.dtpa_name.dtat_data, 142 provider->pv_desc.dtvd_attr.dtpa_name.dtat_class, 143 /* args[] attributes */ 144 provider->pv_desc.dtvd_attr.dtpa_args.dtat_name, 145 provider->pv_desc.dtvd_attr.dtpa_args.dtat_data, 146 provider->pv_desc.dtvd_attr.dtpa_args.dtat_class); 147 148 return buffer; 149} 150 151const char* dt_ld_decode_stability_v1_level(int stability_level) { 152 switch(stability_level) { 153 case DTRACE_STABILITY_INTERNAL: return "INTERNAL"; 154 case DTRACE_STABILITY_PRIVATE: return "PRIVATE"; 155 case DTRACE_STABILITY_OBSOLETE: return "OBSOLETE"; 156 case DTRACE_STABILITY_EXTERNAL: return "EXTERNAL"; 157 case DTRACE_STABILITY_UNSTABLE: return "UNSTABLE"; 158 case DTRACE_STABILITY_EVOLVING: return "EVOLVING"; 159 case DTRACE_STABILITY_STABLE: return "STABLE"; 160 case DTRACE_STABILITY_STANDARD: return "STANDARD"; 161 default: return "ERROR!"; 162 }; 163} 164 165const char* dt_ld_decode_stability_v1_class(int stability_class) { 166 switch(stability_class) { 167 case DTRACE_CLASS_UNKNOWN: return "UNKNOWN"; 168 case DTRACE_CLASS_CPU: return "CPU"; 169 case DTRACE_CLASS_PLATFORM: return "PLATFORM"; 170 case DTRACE_CLASS_GROUP: return "GROUP"; 171 case DTRACE_CLASS_ISA: return "ISA"; 172 case DTRACE_CLASS_COMMON: return "COMMON"; 173 default: return "ERROR!"; 174 }; 175} 176 177std::string dt_ld_decode_stability_v1(const char* provider, const char* stability) 178{ 179 // A validly encoded v1 string: 180 // 181 // ___dtrace_stability$poly$v1$1_1_0_1_1_0_1_1_0_1_1_0_5_5_5 182 // 183 // The #_#_#_ triples only have single digit legal values. 184 185 if (strlen(stability) == 29) { 186 char stability_line_buffer[128]; 187 188 const char* name = dt_ld_decode_stability_v1_level(stability[0] - '0'); 189 const char* data = dt_ld_decode_stability_v1_level(stability[2] - '0'); 190 const char* stability_class = dt_ld_decode_stability_v1_class(stability[4] - '0'); 191 snprintf(stability_line_buffer, sizeof(stability_line_buffer), "#pragma D attributes %s/%s/%s provider %s provider\n", name, data, stability_class, provider); 192 std::string decoded_stability(stability_line_buffer); 193 stability += 6; // Skip to the next encoding 194 195 name = dt_ld_decode_stability_v1_level(stability[0] - '0'); 196 data = dt_ld_decode_stability_v1_level(stability[2] - '0'); 197 stability_class = dt_ld_decode_stability_v1_class(stability[4] - '0'); 198 snprintf(stability_line_buffer, sizeof(stability_line_buffer), "#pragma D attributes %s/%s/%s provider %s module\n", name, data, stability_class, provider); 199 decoded_stability += stability_line_buffer; 200 stability += 6; // Skip to the next encoding 201 202 name = dt_ld_decode_stability_v1_level(stability[0] - '0'); 203 data = dt_ld_decode_stability_v1_level(stability[2] - '0'); 204 stability_class = dt_ld_decode_stability_v1_class(stability[4] - '0'); 205 snprintf(stability_line_buffer, sizeof(stability_line_buffer), "#pragma D attributes %s/%s/%s provider %s function\n", name, data, stability_class, provider); 206 decoded_stability += stability_line_buffer; 207 stability += 6; // Skip to the next encoding 208 209 name = dt_ld_decode_stability_v1_level(stability[0] - '0'); 210 data = dt_ld_decode_stability_v1_level(stability[2] - '0'); 211 stability_class = dt_ld_decode_stability_v1_class(stability[4] - '0'); 212 snprintf(stability_line_buffer, sizeof(stability_line_buffer), "#pragma D attributes %s/%s/%s provider %s name\n", name, data, stability_class, provider); 213 decoded_stability += stability_line_buffer; 214 stability += 6; // Skip to the next encoding 215 216 name = dt_ld_decode_stability_v1_level(stability[0] - '0'); 217 data = dt_ld_decode_stability_v1_level(stability[2] - '0'); 218 stability_class = dt_ld_decode_stability_v1_class(stability[4] - '0'); 219 snprintf(stability_line_buffer, sizeof(stability_line_buffer), "#pragma D attributes %s/%s/%s provider %s args\n", name, data, stability_class, provider); 220 221 return decoded_stability + stability_line_buffer; 222 } 223 224 return "/* Error decoding v1 stability string */"; 225} 226 227static std::vector<std::string> split(const std::string& s, char delim) 228{ 229 std::vector<std::string> elems; 230 std::stringstream ss(s); 231 std::string item; 232 while(std::getline(ss, item, delim)) { 233 elems.push_back(item); 234 } 235 return elems; 236} 237 238std::string dt_ld_decode_stability(std::string encoding) 239{ 240 // A validly encoded v1 string: 241 // 242 // ___dtrace_stability$poly$v1$1_1_0_1_1_0_1_1_0_1_1_0_5_5_5 243 244 std::vector<std::string> elements = split(encoding, dtrace_separator_char); 245 246 if (elements.size() == 4) { 247 if (elements[2] == "v1") { 248 return dt_ld_decode_stability_v1(elements[1].c_str(), elements[3].c_str()); 249 } 250 } 251 252 // Wow, no good way to handle error conditions here. 253 return "Unhandled stability encoding version"; 254} 255 256#pragma mark - 257#pragma mark typedef encoding / decoding 258 259// DTrace typedefs a small number of default types by default. 260// Unfortunately, these are not base types, and so they are 261// encoded as specialized types. This works fine until link 262// time, when DTrace sees the encoding as an attempt to redefine 263// an existing type, and fails the link. This method creates 264// a dictionary of types to ignore when encoding. 265 266typedef std::unordered_set<std::string> ExclusionTypeSet; 267 268static ExclusionTypeSet* base_dtrace_typeset() { 269 ExclusionTypeSet* typeset = new ExclusionTypeSet(); 270 271 // First walk all 32 bit typedefs 272 extern const dt_typedef_t _dtrace_typedefs_32[]; 273 const dt_typedef_t *iter = _dtrace_typedefs_32; 274 for (; iter->dty_src != NULL; iter++) { 275 typeset->insert(std::string(iter->dty_dst)); 276 } 277 278 // These are almost certainly the same, but just in case... 279 // Walk all 64 bit typedefs 280 extern const dt_typedef_t _dtrace_typedefs_64[]; 281 iter = _dtrace_typedefs_64; 282 for (; iter->dty_src != NULL; iter++) { 283 typeset->insert(std::string(iter->dty_dst)); 284 } 285 286 return typeset; 287} 288 289static bool is_base_dtrace_type(std::string type) { 290 static ExclusionTypeSet* exclusion_types = base_dtrace_typeset(); 291 return exclusion_types->find(type) != exclusion_types->end(); 292} 293 294// 295// If the input type is a pointer, return the type pointed to. 296// This method is recursive, it will walk back a chain of pointers 297// until it reaches a non pointer type. 298// 299// If the original type is not a pointer, it is returned unchanged. 300 301static ctf_id_t dt_ld_strip_pointers(ctf_file_t *file, ctf_id_t type) { 302 if (ctf_type_kind(file, type) == CTF_K_POINTER) { 303 return dt_ld_strip_pointers(file, ctf_type_reference(file, type)); 304 } 305 306 return type; 307} 308 309// This method requires the caller have a valid NSAutoreleasePool 310// 311// This method works as follows: 312// 313// 1) Strip any pointer'dness from the arg type 314// 2) If the resulting type != a base type, assume it needs a typedef 315// 3) We *DO NOT* retain the original type. Everything that is typedef'd is forced to int, I.E. 316// 317// original: typedef float*** foo_t 318// encoded: typedef int foo_t 319 320typedef std::unordered_map< std::string, std::string > TypeEncodingMap; 321 322static int dt_ld_probe_encode_typedef_iter(dt_idhash_t *dhp, dt_ident_t *idp, void *data) 323{ 324 TypeEncodingMap* encoded_types_map = (TypeEncodingMap*)data; 325 dt_probe_t* probe = (dt_probe_t*)idp->di_data; 326 dt_node_t* node; 327 for (node = probe->pr_nargs; node != NULL; node = node->dn_list) { 328 ctf_id_t stripped_of_pointers = dt_ld_strip_pointers(node->dn_ctfp, node->dn_type); 329 ctf_id_t base = ctf_type_resolve(node->dn_ctfp, stripped_of_pointers); 330 if (base != stripped_of_pointers) { 331 ssize_t size = ctf_type_lname(node->dn_ctfp, stripped_of_pointers, NULL, 0) + 1; 332 char* buf = (char*)alloca(size); 333 ctf_type_lname(node->dn_ctfp, stripped_of_pointers, buf, size); 334 std::string type_key(buf); 335 336 // Gah. DTrace always typedefs a certain set of types, which are not base types. 337 // See <rdar://problem/5194316>. I haven't been able to discover a way to differentiate 338 // the predefined types from those created in provider.d files, so we do this the hard 339 // way. 340 341 if (!is_base_dtrace_type(type_key)) { 342 if (encoded_types_map->find(type_key) == encoded_types_map->end()) { 343 encoded_types_map->insert(TypeEncodingMap::value_type(type_key, dt_ld_encode_string(type_key.c_str()))); 344 } 345 } 346 } 347 } 348 349 return 0; 350} 351 352char* dt_ld_encode_typedefs(char* provider_name, dt_provider_t *provider) 353{ 354 TypeEncodingMap encoded_types_map; 355 356 dt_idhash_iter(provider->pv_probes, dt_ld_probe_encode_typedef_iter, (void*)&encoded_types_map); 357 358 char encoded_typedefs_line_buffer[256]; 359 snprintf(encoded_typedefs_line_buffer, sizeof(encoded_typedefs_line_buffer), "%s%s%s%s%s", 360 dtrace_typedefs_encoding_prefix, 361 dtrace_separator, 362 provider_name, 363 dtrace_separator, 364 dtrace_typedefs_version); 365 std::string encoded_types(encoded_typedefs_line_buffer); 366 367 for (TypeEncodingMap::iterator it = encoded_types_map.begin(); it != encoded_types_map.end(); ++it) { 368 encoded_types += dtrace_separator; 369 encoded_types += it->second; 370 } 371 372 if (_dtrace_debug) { 373 for (TypeEncodingMap::iterator it = encoded_types_map.begin(); it != encoded_types_map.end(); ++it) { 374 dt_dprintf("dt_ld encoding type %s as %s\n", it->first.c_str(), it->second.c_str()); 375 } 376 } 377 378 return strdup(encoded_types.c_str()); 379} 380 381std::string dt_ld_decode_typedefs_v1(std::vector<std::string>& typedefs) 382{ 383 std::string decoded; 384 385 for (size_t i = 3; i < typedefs.size(); i++) { 386 char line_buffer[128]; 387 snprintf(line_buffer, sizeof(line_buffer), "typedef int %s;\n", dt_ld_decode_string(typedefs[i].c_str()).c_str()); 388 decoded += line_buffer; 389 } 390 391 return decoded; 392} 393 394std::string dt_ld_decode_typedefs(std::string encoding, std::string* version_out) 395{ 396 std::vector<std::string> elements = split(encoding, dtrace_separator_char); 397 398 std::string version; 399 if (elements.size() >= 3) { 400 version = elements[2]; 401 if (version_out) { 402 *version_out = elements[2]; 403 } 404 } 405 406 // Is anything actually encoded? 407 if (elements.size() >= 4) { 408 // Both v1 & v2 use the same format, v2 is a subset of v1 (with the fix for <rdar://problem/5194316>) 409 if (version == "v1" || version == "v2") { 410 return dt_ld_decode_typedefs_v1(elements); 411 } 412 413 return "Unhandled typedefs encoding version"; 414 } 415 416 return ""; 417} 418 419#pragma mark - 420#pragma mark probe encoding / decoding 421 422char* dt_ld_encode_probe(char* provider_name, char* probe_name, dt_probe_t* probe) 423{ 424 char line_buffer[256]; 425 snprintf(line_buffer, sizeof(line_buffer), "%s%s%s%s%s%s%s", 426 dtrace_probe_encoding_prefix, 427 dtrace_separator, 428 provider_name, 429 dtrace_separator, 430 probe_name, 431 dtrace_separator, 432 dtrace_probe_version); 433 434 std::string encoded(line_buffer); 435 436 for (int i = 0; i < probe->pr_nargc; i++) { 437 dt_node_t* node = probe->pr_nargv[i]; 438 ssize_t size = ctf_type_lname(node->dn_ctfp, node->dn_type, NULL, 0) + 1; 439 char* buf = (char*)alloca(size); 440 ctf_type_lname(node->dn_ctfp, node->dn_type, buf, size); 441 encoded += dtrace_separator_char; 442 encoded += dt_ld_encode_string(buf); 443 } 444 445 return strdup(encoded.c_str()); 446} 447 448std::string dt_ld_decode_probe_v1(std::vector<std::string>& arguments) 449{ 450 std::string decoded; 451 452 for (size_t i = 4; i < arguments.size(); ++i) { 453 decoded += dt_ld_decode_string(arguments[i].c_str()); 454 if (i+1 < arguments.size()) { 455 decoded += ','; 456 } 457 } 458 459 return decoded; 460} 461 462std::string dt_ld_decode_probe(std::string encoding) 463{ 464 std::vector<std::string> elements = split(encoding, dtrace_separator_char); 465 466 if (elements.size() > 3) { 467 if (elements[3] == "v1") { 468 std::string probe("\tprobe "); 469 probe += elements[2]; 470 probe += '('; 471 472 if (elements.size() > 4) { 473 probe += dt_ld_decode_probe_v1(elements); 474 } 475 476 probe += ");"; 477 478 return probe; 479 } 480 } 481 482 // Wow, no good way to handle error conditions here. 483 return "Unhandled probe encoding version"; 484} 485 486#pragma mark - 487#pragma mark isenabled encoding 488 489char* dt_ld_encode_isenabled(char* provider_name, char* probe_name) 490{ 491 // "isenabled" probe info is encoded as (dtrace_isenabled_encoding_prefix)(providerName)(probe_name) 492 size_t bufsize = sizeof(dtrace_isenabled_encoding_prefix) + 493 sizeof(dtrace_separator) + 494 strlen(provider_name) + 495 sizeof(dtrace_separator) + 496 strlen(probe_name) + 497 1; // NULL terminator 498 499 char* buffer = (char*)malloc(bufsize); 500 501 snprintf(buffer, bufsize, "%s%s%s%s%s%s%s", 502 dtrace_isenabled_encoding_prefix, 503 dtrace_separator, 504 provider_name, 505 dtrace_separator, 506 probe_name, 507 dtrace_separator, 508 dtrace_isenabled_version); 509 510 return buffer; 511} 512 513#pragma mark - 514#pragma mark D Script regeneration 515 516std::string dt_ld_decode_script(std::string stability, std::string typedefs, std::vector<std::string>& probes) 517{ 518 std::string decoded_typedefs = dt_ld_decode_typedefs(typedefs, NULL); 519 520 std::string script = dt_ld_decode_typedefs(typedefs, NULL); 521 522 script += "\nprovider "; 523 // Maybe we should pass the provider name in? Do some error checking? 524 script += split(stability, dtrace_separator_char)[1]; // provider name 525 script += " {\n"; 526 527 std::unordered_set<std::string> uniqued_probes; 528 for (std::vector<std::string>::iterator it = probes.begin(); it < probes.end(); ++it) { 529 std::vector<std::string> components = split(*it, dtrace_separator_char); 530 531 if (components.size() < 3) // Can't be a probe spec 532 continue; 533 534 if (components[0] != dtrace_probe_decoding_prefix) 535 continue; 536 537 std::string probe_name = components[2]; 538 539 if (uniqued_probes.count(probe_name)) 540 continue; 541 542 uniqued_probes.insert(probe_name); 543 script += dt_ld_decode_probe(*it); 544 script += '\n'; 545 } 546 547 script += "};\n\n"; 548 script += dt_ld_decode_stability(stability); 549 script += '\n'; 550 551 return script; 552} 553 554#pragma mark - 555#pragma mark Linker support 556 557static int linker_flags(cpu_type_t cpu) 558{ 559 int oflags = 0; 560 561 oflags |= DTRACE_O_NODEV; 562 563 if(cpu & CPU_ARCH_ABI64) 564 oflags |= DTRACE_O_LP64; 565 else 566 oflags |= DTRACE_O_ILP32; 567 568 return oflags; 569} 570 571static void set_options(dtrace_hdl_t* dtp) 572{ 573 (void) dtrace_setopt(dtp, "linkmode", "dynamic"); 574 (void) dtrace_setopt(dtp, "unodefs", NULL); 575 (void) dtrace_setopt(dtp, "nolibs", NULL); /* In case /usr/lib/dtrace/ * is broken, we can succeed. */ 576} 577 578static int register_probes(dtrace_hdl_t* dtp, int count, const char* labels[], const char* functions[]) 579{ 580 int i; 581 int is_enabled = 0; 582 583 for(i = 0; i < count; i++) { 584 const char* label = labels[i]; 585 const char* label0 = label; 586 587 if(strncmp(label, dtrace_isenabled_decoding_prefix, sizeof(dtrace_isenabled_decoding_prefix) - 1) == 0) { 588 // skip prefix 589 label += sizeof(dtrace_isenabled_decoding_prefix) - 1; 590 is_enabled = 1; 591 } else if (strncmp(label, dtrace_probe_decoding_prefix, sizeof(dtrace_probe_decoding_prefix) - 1) == 0) { 592 // skip prefix 593 label += sizeof(dtrace_probe_decoding_prefix) - 1; 594 is_enabled = 0; 595 } else { 596 fprintf(stderr, "error: invalid probe marker: %s\n", label0); 597 return -1; 598 } 599 600 // skip separator 601 602 label += sizeof(dtrace_separator) - 1; 603 604 // Grab the provider name 605 606 const char* end = strstr(label, dtrace_separator); 607 if(!end) { 608 fprintf(stderr, "error: probe marker contains no provider name: %s\n", label0); 609 return -1; 610 } 611 612 char* provider_name = (char*)malloc(end - label + 1); 613 memcpy(provider_name, label, (end - label)); 614 provider_name[end - label] = 0; 615 616 // Skip the separator 617 618 label = end + sizeof(dtrace_separator) - 1; 619 620 // Grab the probe name 621 622 end = strstr(label, dtrace_separator); 623 624 if(!end) { 625 fprintf(stderr, "error: probe marker contains no probe name: %s\n", label0); 626 return -1; 627 } 628 629 char* probe_name = (char*)malloc(end - label + 1); 630 memcpy(probe_name, label, (end - label)); 631 probe_name[end - label] = 0; 632 probe_name = strhyphenate(probe_name); 633 634 // now, register the probe 635 dt_provider_t *provider = dt_provider_lookup(dtp, provider_name); 636 if(!provider) { 637 fprintf(stderr, "error: provider %s doesn't exist\n", provider_name); 638 return -1; 639 } 640 641 dt_probe_t* probe = dt_probe_lookup(provider, probe_name); 642 if(!probe) { 643 fprintf(stderr, "error: probe %s doesn't exist\n", probe_name); 644 return -1; 645 } 646 647 // The "raw" function names provided by the linker will have an underscore 648 // prepended. Remove it before registering the probe function. 649 const char* function_name = functions[i]; 650 if (function_name[0] == '_') 651 function_name++; 652 653 if(dt_probe_define(provider, probe, function_name, NULL, i, is_enabled)) { 654 fprintf(stderr, "error: couldn't define probe %s:::%s\n", provider_name, probe_name); 655 return -1; 656 } 657 658 free(provider_name); // free() of provider_name 659 free(probe_name); // free() of probe_name 660 } 661 662 return 0; 663} 664 665int register_offsets(dof_hdr_t* header, int count, uint64_t offsetsInDOF[]) 666{ 667 dof_sec_t* sections = (dof_sec_t*)((char*)header + header->dofh_secoff); 668 669 int i; 670 671 for(i = 0; i < count; i++) 672 offsetsInDOF[i] = (uint64_t)-1; 673 674 for(i = 0; i < header->dofh_secnum; i++) { 675 switch(sections[i].dofs_type) { 676 case DOF_SECT_PROFFS: 677 case DOF_SECT_PRENOFFS: 678 { 679 // As each probe is defined, it gets a uint32_t entry that indicates its offset. 680 // In the Sun DOF, this is the offset from the start of the function the probe 681 // resides in. We use it to mean "offset to this probe from the start of the 682 // DOF section". We stored the relocation_index as a placeholder in the 683 // register_probes() function. 684 uint32_t* probe_offsets = (uint32_t*)((char*)header + sections[i].dofs_offset); 685 uint32_t j, count = sections[i].dofs_size / sizeof(uint32_t); 686 for (j=0; j<count; j++) { 687 int relocation_index = probe_offsets[j]; 688 offsetsInDOF[relocation_index] = (uint64_t)(unsigned long)((char*)&probe_offsets[j] - (char*)header); 689 } 690 } 691 break; 692 } 693 } 694 695 return 0; 696} 697 698void* dtrace_ld_create_dof(cpu_type_t cpu, // [provided by linker] target architecture 699 unsigned int typeCount, // [provided by linker] number of stability or typedef symbol names 700 const char* typeNames[], // [provided by linker] stability or typedef symbol names 701 unsigned int probeCount, // [provided by linker] number of probe or isenabled locations 702 const char* probeNames[], // [provided by linker] probe or isenabled symbol names 703 const char* probeWithin[], // [provided by linker] function name containing probe or isenabled 704 uint64_t offsetsInDOF[], // [allocated by linker, populated by DTrace] per-probe offset in the DOF 705 size_t* size) // [allocated by linker, populated by DTrace] size of the DOF) 706{ 707 bool printReconstructedScript = getenv("DTRACE_PRINT_RECONSTRUCTED_SCRIPT") != NULL; 708 709 int i, err; 710 const char* stability = NULL; 711 const char* typedefs = NULL; 712 713 // First, find a valid stability and typedefs. 714 for (i=0; i<typeCount; i++) { 715 if (strncmp(typeNames[i], dtrace_stability_decoding_prefix, sizeof(dtrace_stability_decoding_prefix)-1) == 0) { 716 if (stability == NULL) { 717 stability = typeNames[i]; 718 } else if (strcmp(stability, typeNames[i]) != 0) { 719 fprintf(stderr, "error: Found conflicting dtrace stability info:\n%s\n%s\n", stability, typeNames[i]); 720 return NULL; 721 } 722 } else if (strncmp(typeNames[i], dtrace_typedefs_decoding_prefix, sizeof(dtrace_typedefs_decoding_prefix)-1) == 0) { 723 if (typedefs == NULL) { 724 typedefs = typeNames[i]; 725 } else if (strcmp(typedefs, typeNames[i]) != 0) { 726 // let's see if it's from a version conflict. 727 std::string existing_info; 728 std::string new_info; 729 dt_ld_decode_typedefs(typedefs, &existing_info); 730 dt_ld_decode_typedefs(typeNames[i], &new_info); 731 if (existing_info != new_info) { 732 fprintf(stderr, 733 "error: Found dtrace typedefs generated by " 734 "different versions of dtrace:\n%s (%s)\n%s (%s)\n", 735 typedefs, existing_info.c_str(), 736 typeNames[i], new_info.c_str()); 737 fprintf(stderr, "Please try regenerating all dtrace created " 738 "header files with the same version of " 739 "dtrace before rebuilding your project.\n"); 740 } else { 741 fprintf(stderr, "error: Found conflicting dtrace typedefs info:\n%s\n%s\n", typedefs, typeNames[i]); 742 } 743 return NULL; 744 } 745 } else { 746 fprintf(stderr, "error: Found unhandled dtrace typename prefix: %s\n", typeNames[i]); 747 return NULL; 748 } 749 } 750 751 if (stability == NULL) { 752 fprintf(stderr, "error: Must have a valid dtrace stability entry\n"); 753 return NULL; 754 } 755 756 if (typedefs == NULL) { 757 fprintf(stderr, "error: Must have a a valid dtrace typedefs entry\n"); 758 return NULL; 759 } 760 761 // Recreate the provider.d script 762 std::vector<std::string> probes; 763 int is_enabled_probes = 0; 764 for (i=0; i<probeCount; i++) { 765 if (strncmp(probeNames[i], dtrace_probe_decoding_prefix, sizeof(dtrace_probe_decoding_prefix)-1) == 0) { 766 // Assert this belongs to the correct provider! 767 probes.push_back(std::string(probeNames[i])); 768 } else if (strncmp(probeNames[i], dtrace_isenabled_decoding_prefix, sizeof(dtrace_isenabled_decoding_prefix)-1) == 0) { 769 // Assert this belongs to the correct provider! 770 probes.push_back(std::string(probeNames[i])); 771 is_enabled_probes++; 772 } else { 773 fprintf(stderr, "error: Found unhandled dtrace probe prefix: %s\n", probeNames[i]); 774 } 775 } 776 777 if (probes.size() == 0) { 778 fprintf(stderr, "error: Dtrace provider %s has no probes\n", stability); 779 return NULL; 780 } 781 782 std::string dscript = dt_ld_decode_script(std::string(stability), std::string(typedefs), probes); 783 784 dtrace_hdl_t* dtp = dtrace_open(DTRACE_VERSION, 785 linker_flags(cpu), 786 &err); 787 788 if(!dtp) { 789 fprintf(stderr,"error: Failed to initialize dtrace: %s\n", dtrace_errmsg(NULL, err)); 790 return NULL; 791 } 792 793 set_options(dtp); 794 795 dtrace_prog_t* program = dtrace_program_strcompile(dtp, 796 dscript.c_str(), 797 DTRACE_PROBESPEC_NONE, 798 0, 799 0, 800 NULL); 801 802 if(!program) { 803 fprintf(stderr, "error: Could not compile reconstructed dtrace script:\n\n%s\n", dscript.c_str()); 804 return NULL; 805 } 806 807 if (_dtrace_debug || printReconstructedScript) { 808 fprintf(stderr, "\n%s\n", dscript.c_str()); 809 } 810 811 if(register_probes(dtp, probeCount, probeNames, probeWithin)) { 812 fprintf(stderr, "error: Could not register probes\n"); 813 return NULL; 814 } 815 816 dof_hdr_t* dof = (dof_hdr_t*)dtrace_dof_create(dtp, program, DTRACE_D_PROBES | DTRACE_D_STRIP); 817 818 if(register_offsets(dof, probeCount, offsetsInDOF)) { 819 fprintf(stderr, "error: Could not register DOF offsets\n"); 820 return NULL; 821 } 822 823 *size = dof->dofh_filesz; 824 825 void* return_data = malloc(*size); 826 memcpy(return_data, dof, *size); 827 828 if(needs_swapping(host_arch, cpu)) 829 dtrace_dof_byteswap((dof_hdr_t*)return_data); 830 831 dtrace_dof_destroy(dtp, dof); 832 dtrace_close(dtp); 833 834 return return_data; 835} 836