--- /dev/null
+/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <stdint.h>
+#include <math.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include <vector>
+#include <map>
+#include <ext/hash_map>
+
+#include "ld.hpp"
+#include "dtrace_dof.h"
+
+// prototype for entry point in libdtrace.dylib
+typedef uint8_t* (*createdof_func_t)(cpu_type_t, unsigned int, const char*[], unsigned int, const char*[], const char*[], uint64_t offsetsInDOF[], size_t* size);
+
+
+namespace ld {
+namespace passes {
+namespace dtrace {
+
+class File; // forward reference
+
+class Atom : public ld::Atom {
+public:
+ Atom(class File& f, const char* n, const uint8_t* content, uint64_t sz);
+
+ virtual ld::File* file() const { return (ld::File*)&_file; }
+ virtual bool translationUnitSource(const char** dir, const char** ) const
+ { return false; }
+ virtual const char* name() const { return _name; }
+ virtual uint64_t size() const { return _size; }
+ virtual uint64_t objectAddress() const { return 0; }
+ virtual void copyRawContent(uint8_t buffer[]) const
+ { memcpy(buffer, _content, _size); }
+ virtual void setScope(Scope) { }
+ virtual ld::Fixup::iterator fixupsBegin() const { return &_fixups[0]; }
+ virtual ld::Fixup::iterator fixupsEnd() const { return &_fixups[_fixups.size()]; }
+
+protected:
+ friend class File;
+ virtual ~Atom() {}
+
+ class File& _file;
+ const char* _name;
+ const uint8_t* _content;
+ uint64_t _size;
+ mutable std::vector<ld::Fixup> _fixups;
+};
+
+
+class File : public ld::File
+{
+public:
+ File(const char* segmentName, const char* sectionName, const char* pth,
+ const uint8_t fileContent[], uint64_t fileLength, uint32_t ord,
+ const char* symbolName="dof")
+ : ld::File(pth, 0, ord),
+ _atom(*this, symbolName, fileContent, fileLength),
+ _section(segmentName, sectionName, ld::Section::typeDtraceDOF) { }
+ virtual ~File() {}
+
+ virtual bool forEachAtom(AtomHandler& h) const { h.doAtom(_atom); return true; }
+ virtual bool justInTimeforEachAtom(const char* name, AtomHandler&) const { return false; }
+
+ void reserveFixups(unsigned int count) { _atom._fixups.reserve(count); }
+ void addSectionFixup(const ld::Fixup& f) { _atom._fixups.push_back(f); }
+ ld::Atom& atom() { return _atom; }
+private:
+ friend class Atom;
+
+ Atom _atom;
+ ld::Section _section;
+};
+
+Atom::Atom(File& f, const char* n, const uint8_t* content, uint64_t sz)
+ : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever,
+ ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
+ symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
+ _file(f), _name(strdup(n)), _content(content), _size(sz) {}
+
+
+
+class CStringEquals
+{
+public:
+ bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
+};
+
+struct DTraceProbeInfo {
+ DTraceProbeInfo(const ld::Atom* a, uint32_t o, const char* n) : atom(a), offset(o), probeName(n) {}
+ const ld::Atom* atom;
+ uint32_t offset;
+ const char* probeName;
+};
+typedef __gnu_cxx::hash_map<const char*, std::vector<DTraceProbeInfo>, __gnu_cxx::hash<const char*>, CStringEquals> ProviderToProbes;
+typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> CStringSet;
+
+
+
+void doPass(const Options& opts, ld::Internal& internal)
+{
+ static bool log = false;
+
+ // only make __dof section in final linked images
+ if ( opts.outputKind() == Options::kObjectFile )
+ return;
+
+ // scan all atoms looking for dtrace probes
+ std::vector<DTraceProbeInfo> probeSites;
+ std::vector<DTraceProbeInfo> isEnabledSites;
+ std::map<const ld::Atom*,CStringSet> atomToDtraceTypes;
+ for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
+ ld::Internal::FinalSection* sect = *sit;
+ if ( sect->type() != ld::Section::typeCode )
+ continue;
+ for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
+ const ld::Atom* atom = *ait;
+ for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
+ switch ( fit->kind ) {
+ case ld::Fixup::kindStoreX86DtraceCallSiteNop:
+ case ld::Fixup::kindStorePPCDtraceCallSiteNop:
+ case ld::Fixup::kindStoreARMDtraceCallSiteNop:
+ case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
+ probeSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
+ break;
+ case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
+ case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
+ case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
+ isEnabledSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
+ break;
+ case ld::Fixup::kindDtraceExtra:
+ atomToDtraceTypes[atom].insert(fit->u.name);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // if no probes, we're done
+ if ( (probeSites.size() == 0) && (isEnabledSites.size() == 0) )
+ return;
+
+ ld::Fixup::Kind storeKind = ld::Fixup::kindNone;
+ switch ( opts.architecture() ) {
+ case CPU_TYPE_POWERPC:
+ case CPU_TYPE_POWERPC64:
+ storeKind = ld::Fixup::kindStoreBigEndian32;
+ break;
+ case CPU_TYPE_I386:
+ case CPU_TYPE_X86_64:
+ case CPU_TYPE_ARM:
+ storeKind = ld::Fixup::kindStoreLittleEndian32;
+ break;
+ default:
+ throw "unsupported arch for DOF";
+ }
+
+ // partition probes by provider name
+ // The symbol names looks like:
+ // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
+ // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
+ ProviderToProbes providerToProbes;
+ std::vector<DTraceProbeInfo> emptyList;
+ for(std::vector<DTraceProbeInfo>::iterator it = probeSites.begin(); it != probeSites.end(); ++it) {
+ // ignore probes in functions that were coalesed away rdar://problem/5628149
+ if ( it->atom->coalescedAway() )
+ continue;
+ const char* providerStart = &it->probeName[16];
+ const char* providerEnd = strchr(providerStart, '$');
+ if ( providerEnd != NULL ) {
+ char providerName[providerEnd-providerStart+1];
+ strlcpy(providerName, providerStart, providerEnd-providerStart+1);
+ ProviderToProbes::iterator pos = providerToProbes.find(providerName);
+ if ( pos == providerToProbes.end() ) {
+ const char* dup = strdup(providerName);
+ providerToProbes[dup] = emptyList;
+ }
+ providerToProbes[providerName].push_back(*it);
+ }
+ }
+ for(std::vector<DTraceProbeInfo>::iterator it = isEnabledSites.begin(); it != isEnabledSites.end(); ++it) {
+ // ignore probes in functions that were coalesed away rdar://problem/5628149
+ if ( it->atom->coalescedAway() )
+ continue;
+ const char* providerStart = &it->probeName[20];
+ const char* providerEnd = strchr(providerStart, '$');
+ if ( providerEnd != NULL ) {
+ char providerName[providerEnd-providerStart+1];
+ strlcpy(providerName, providerStart, providerEnd-providerStart+1);
+ ProviderToProbes::iterator pos = providerToProbes.find(providerName);
+ if ( pos == providerToProbes.end() ) {
+ const char* dup = strdup(providerName);
+ providerToProbes[dup] = emptyList;
+ }
+ providerToProbes[providerName].push_back(*it);
+ }
+ }
+
+ // create a DOF section for each provider
+ int dofIndex=1;
+ CStringSet sectionNamesUsed;
+ for(ProviderToProbes::iterator pit = providerToProbes.begin(); pit != providerToProbes.end(); ++pit, ++dofIndex) {
+ const char* providerName = pit->first;
+ const std::vector<DTraceProbeInfo>& probes = pit->second;
+
+ // open library and find dtrace_create_dof()
+ void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY);
+ if ( handle == NULL )
+ throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
+ createdof_func_t pCreateDOF = (createdof_func_t)dlsym(handle, "dtrace_ld_create_dof");
+ if ( pCreateDOF == NULL )
+ throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
+ // build list of typedefs/stability infos for this provider
+ CStringSet types;
+ for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
+ std::map<const ld::Atom*,CStringSet>::iterator pos = atomToDtraceTypes.find(it->atom);
+ if ( pos != atomToDtraceTypes.end() ) {
+ for(CStringSet::iterator sit = pos->second.begin(); sit != pos->second.end(); ++sit) {
+ const char* providerStart = strchr(*sit, '$')+1;
+ const char* providerEnd = strchr(providerStart, '$');
+ if ( providerEnd != NULL ) {
+ char aProviderName[providerEnd-providerStart+1];
+ strlcpy(aProviderName, providerStart, providerEnd-providerStart+1);
+ if ( strcmp(aProviderName, providerName) == 0 )
+ types.insert(*sit);
+ }
+ }
+ }
+ }
+ int typeCount = types.size();
+ const char* typeNames[typeCount];
+ //fprintf(stderr, "types for %s:\n", providerName);
+ uint32_t index = 0;
+ for(CStringSet::iterator it = types.begin(); it != types.end(); ++it) {
+ typeNames[index] = *it;
+ //fprintf(stderr, "\t%s\n", *it);
+ ++index;
+ }
+
+ // build list of probe/isenabled sites
+ const uint32_t probeCount = probes.size();
+ const char* probeNames[probeCount];
+ const char* funtionNames[probeCount];
+ uint64_t offsetsInDOF[probeCount];
+ index = 0;
+ for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
+ probeNames[index] = it->probeName;
+ funtionNames[index] = it->atom->name();
+ offsetsInDOF[index] = 0;
+ ++index;
+ }
+ if ( log ) {
+ fprintf(stderr, "calling libtrace to create DOF:\n");
+ fprintf(stderr, " types::\n");
+ for(int i=0; i < typeCount; ++i)
+ fprintf(stderr, " [%u]\t %s\n", i, typeNames[i]);
+ fprintf(stderr, " probes::\n");
+ for(uint32_t i=0; i < probeCount; ++i)
+ fprintf(stderr, " [%u]\t %s in %s\n", i, probeNames[i], funtionNames[i]);
+ }
+
+ // call dtrace library to create DOF section
+ size_t dofSectionSize;
+ uint8_t* p = (*pCreateDOF)(opts.architecture(), typeCount, typeNames, probeCount, probeNames, funtionNames, offsetsInDOF, &dofSectionSize);
+ if ( p != NULL ) {
+ char* sectionName = new char[18]; // alloc new string, pass ownership to File()
+ strcpy(sectionName, "__dof_");
+ strlcpy(§ionName[6], providerName, 10);
+ // create unique section name so each DOF is in its own section
+ if ( sectionNamesUsed.count(sectionName) != 0 ) {
+ sectionName[15] = '0';
+ sectionName[16] = '\0';
+ while ( sectionNamesUsed.count(sectionName) != 0 ) {
+ ++sectionName[15];
+ }
+ }
+ sectionNamesUsed.insert(sectionName);
+ char symbolName[strlen(providerName)+64];
+ sprintf(symbolName, "__dtrace_dof_for_provider_%s", providerName);
+ File* f = new File("__TEXT", sectionName, "dtrace", p, dofSectionSize, 0, symbolName);
+ if ( log ) {
+ fprintf(stderr, "libdtrace created DOF of size %ld\n", dofSectionSize);
+ }
+ // add references
+ f->reserveFixups(3*probeCount);
+ for (uint32_t i=0; i < probeCount; ++i) {
+ uint64_t offset = offsetsInDOF[i];
+ //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
+ if ( offset > dofSectionSize )
+ throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize);
+ f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, probes[i].atom));
+ f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, probes[i].offset));
+ f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, &f->atom()));
+ f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k4of4, storeKind));
+ }
+ // insert new section
+ internal.addAtom(f->atom());
+ }
+ else {
+ throw "error creating dtrace DOF section";
+ }
+ }
+
+
+
+}
+
+
+} // namespace dtrace
+} // namespace passes
+} // namespace ld