X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/07feaf2cb00322d025073eb8ec22189ada5e4180..a645023da60d22e86be13f7b4d97adeff8bc6665:/src/ld/passes/dtrace_dof.cpp diff --git a/src/ld/passes/dtrace_dof.cpp b/src/ld/passes/dtrace_dof.cpp new file mode 100644 index 0000000..f847cc0 --- /dev/null +++ b/src/ld/passes/dtrace_dof.cpp @@ -0,0 +1,339 @@ +/* -*- 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 +#include +#include +#include + +#include +#include +#include + +#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 _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, __gnu_cxx::hash, CStringEquals> ProviderToProbes; +typedef __gnu_cxx::hash_set, 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 probeSites; + std::vector isEnabledSites; + std::map atomToDtraceTypes; + for (std::vector::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::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 emptyList; + for(std::vector::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::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& 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::const_iterator it = probes.begin(); it != probes.end(); ++it) { + std::map::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::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