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