133-3
[darwin-xtools.git] / ld64 / src / ld / passes / dtrace_dof.cpp
blob02055f34242a134b36eae90af6ed31b8009e125f
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2009 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
26 #include <stdint.h>
27 #include <math.h>
28 #include <unistd.h>
29 #include <dlfcn.h>
31 #include <vector>
32 #include <map>
33 #include <ext/hash_map>
35 #include "ld.hpp"
36 #include "dtrace_dof.h"
38 // prototype for entry point in libdtrace.dylib
39 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);
42 namespace ld {
43 namespace passes {
44 namespace dtrace {
46 class File; // forward reference
48 class Atom : public ld::Atom {
49 public:
50 Atom(class File& f, const char* n, const uint8_t* content, uint64_t sz);
52 virtual ld::File* file() const { return (ld::File*)&_file; }
53 virtual bool translationUnitSource(const char** dir, const char** ) const
54 { return false; }
55 virtual const char* name() const { return _name; }
56 virtual uint64_t size() const { return _size; }
57 virtual uint64_t objectAddress() const { return 0; }
58 virtual void copyRawContent(uint8_t buffer[]) const
59 { memcpy(buffer, _content, _size); }
60 virtual void setScope(Scope) { }
61 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixups[0]; }
62 virtual ld::Fixup::iterator fixupsEnd() const { return &_fixups[_fixups.size()]; }
64 protected:
65 friend class File;
66 virtual ~Atom() {}
68 class File& _file;
69 const char* _name;
70 const uint8_t* _content;
71 uint64_t _size;
72 mutable std::vector<ld::Fixup> _fixups;
76 class File : public ld::File
78 public:
79 File(const char* segmentName, const char* sectionName, const char* pth,
80 const uint8_t fileContent[], uint64_t fileLength, Ordinal ord,
81 const char* symbolName="dof")
82 : ld::File(pth, 0, ord, Other),
83 _atom(*this, symbolName, fileContent, fileLength),
84 _section(segmentName, sectionName, ld::Section::typeDtraceDOF) { }
85 virtual ~File() {}
87 virtual bool forEachAtom(AtomHandler& h) const { h.doAtom(_atom); return true; }
88 virtual bool justInTimeforEachAtom(const char* name, AtomHandler&) const { return false; }
90 void reserveFixups(unsigned int count) { _atom._fixups.reserve(count); }
91 void addSectionFixup(const ld::Fixup& f) { _atom._fixups.push_back(f); }
92 ld::Atom& atom() { return _atom; }
93 private:
94 friend class Atom;
96 Atom _atom;
97 ld::Section _section;
100 Atom::Atom(File& f, const char* n, const uint8_t* content, uint64_t sz)
101 : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever,
102 ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
103 symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
104 _file(f), _name(strdup(n)), _content(content), _size(sz) {}
108 class CStringEquals
110 public:
111 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
114 struct DTraceProbeInfo {
115 DTraceProbeInfo(const ld::Atom* a, uint32_t o, const char* n) : atom(a), offset(o), probeName(n) {}
116 const ld::Atom* atom;
117 uint32_t offset;
118 const char* probeName;
120 typedef __gnu_cxx::hash_map<const char*, std::vector<DTraceProbeInfo>, __gnu_cxx::hash<const char*>, CStringEquals> ProviderToProbes;
121 typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals> CStringSet;
125 void doPass(const Options& opts, ld::Internal& internal)
127 static bool log = false;
129 // only make __dof section in final linked images
130 if ( opts.outputKind() == Options::kObjectFile )
131 return;
133 // scan all atoms looking for dtrace probes
134 std::vector<DTraceProbeInfo> probeSites;
135 std::vector<DTraceProbeInfo> isEnabledSites;
136 std::map<const ld::Atom*,CStringSet> atomToDtraceTypes;
137 for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
138 ld::Internal::FinalSection* sect = *sit;
139 if ( sect->type() != ld::Section::typeCode )
140 continue;
141 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
142 const ld::Atom* atom = *ait;
143 for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
144 switch ( fit->kind ) {
145 case ld::Fixup::kindStoreX86DtraceCallSiteNop:
146 case ld::Fixup::kindStoreARMDtraceCallSiteNop:
147 case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
148 probeSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
149 break;
150 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
151 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
152 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
153 isEnabledSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
154 break;
155 case ld::Fixup::kindDtraceExtra:
156 atomToDtraceTypes[atom].insert(fit->u.name);
157 break;
158 default:
159 break;
165 // if no probes, we're done
166 if ( (probeSites.size() == 0) && (isEnabledSites.size() == 0) )
167 return;
169 ld::Fixup::Kind storeKind = ld::Fixup::kindNone;
170 switch ( opts.architecture() ) {
171 case CPU_TYPE_I386:
172 case CPU_TYPE_X86_64:
173 case CPU_TYPE_ARM:
174 storeKind = ld::Fixup::kindStoreLittleEndian32;
175 break;
176 default:
177 throw "unsupported arch for DOF";
180 // partition probes by provider name
181 // The symbol names looks like:
182 // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
183 // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
184 ProviderToProbes providerToProbes;
185 std::vector<DTraceProbeInfo> emptyList;
186 for(std::vector<DTraceProbeInfo>::iterator it = probeSites.begin(); it != probeSites.end(); ++it) {
187 // ignore probes in functions that were coalesed away rdar://problem/5628149
188 if ( it->atom->coalescedAway() )
189 continue;
190 const char* providerStart = &it->probeName[16];
191 const char* providerEnd = strchr(providerStart, '$');
192 if ( providerEnd != NULL ) {
193 char providerName[providerEnd-providerStart+1];
194 strlcpy(providerName, providerStart, providerEnd-providerStart+1);
195 ProviderToProbes::iterator pos = providerToProbes.find(providerName);
196 if ( pos == providerToProbes.end() ) {
197 const char* dup = strdup(providerName);
198 providerToProbes[dup] = emptyList;
200 providerToProbes[providerName].push_back(*it);
203 for(std::vector<DTraceProbeInfo>::iterator it = isEnabledSites.begin(); it != isEnabledSites.end(); ++it) {
204 // ignore probes in functions that were coalesed away rdar://problem/5628149
205 if ( it->atom->coalescedAway() )
206 continue;
207 const char* providerStart = &it->probeName[20];
208 const char* providerEnd = strchr(providerStart, '$');
209 if ( providerEnd != NULL ) {
210 char providerName[providerEnd-providerStart+1];
211 strlcpy(providerName, providerStart, providerEnd-providerStart+1);
212 ProviderToProbes::iterator pos = providerToProbes.find(providerName);
213 if ( pos == providerToProbes.end() ) {
214 const char* dup = strdup(providerName);
215 providerToProbes[dup] = emptyList;
217 providerToProbes[providerName].push_back(*it);
221 // create a DOF section for each provider
222 int dofIndex=1;
223 CStringSet sectionNamesUsed;
224 for(ProviderToProbes::iterator pit = providerToProbes.begin(); pit != providerToProbes.end(); ++pit, ++dofIndex) {
225 const char* providerName = pit->first;
226 const std::vector<DTraceProbeInfo>& probes = pit->second;
228 // open library and find dtrace_create_dof()
229 void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY);
230 if ( handle == NULL )
231 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
232 createdof_func_t pCreateDOF = (createdof_func_t)dlsym(handle, "dtrace_ld_create_dof");
233 if ( pCreateDOF == NULL )
234 throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
235 // build list of typedefs/stability infos for this provider
236 CStringSet types;
237 for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
238 std::map<const ld::Atom*,CStringSet>::iterator pos = atomToDtraceTypes.find(it->atom);
239 if ( pos != atomToDtraceTypes.end() ) {
240 for(CStringSet::iterator sit = pos->second.begin(); sit != pos->second.end(); ++sit) {
241 const char* providerStart = strchr(*sit, '$')+1;
242 const char* providerEnd = strchr(providerStart, '$');
243 if ( providerEnd != NULL ) {
244 char aProviderName[providerEnd-providerStart+1];
245 strlcpy(aProviderName, providerStart, providerEnd-providerStart+1);
246 if ( strcmp(aProviderName, providerName) == 0 )
247 types.insert(*sit);
252 int typeCount = types.size();
253 const char* typeNames[typeCount];
254 //fprintf(stderr, "types for %s:\n", providerName);
255 uint32_t index = 0;
256 for(CStringSet::iterator it = types.begin(); it != types.end(); ++it) {
257 typeNames[index] = *it;
258 //fprintf(stderr, "\t%s\n", *it);
259 ++index;
262 // build list of probe/isenabled sites
263 const uint32_t probeCount = probes.size();
264 const char* probeNames[probeCount];
265 const char* funtionNames[probeCount];
266 uint64_t offsetsInDOF[probeCount];
267 index = 0;
268 for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
269 probeNames[index] = it->probeName;
270 funtionNames[index] = it->atom->name();
271 offsetsInDOF[index] = 0;
272 ++index;
274 if ( log ) {
275 fprintf(stderr, "calling libtrace to create DOF:\n");
276 fprintf(stderr, " types::\n");
277 for(int i=0; i < typeCount; ++i)
278 fprintf(stderr, " [%u]\t %s\n", i, typeNames[i]);
279 fprintf(stderr, " probes::\n");
280 for(uint32_t i=0; i < probeCount; ++i)
281 fprintf(stderr, " [%u]\t %s in %s\n", i, probeNames[i], funtionNames[i]);
284 // call dtrace library to create DOF section
285 size_t dofSectionSize;
286 uint8_t* p = (*pCreateDOF)(opts.architecture(), typeCount, typeNames, probeCount, probeNames, funtionNames, offsetsInDOF, &dofSectionSize);
287 if ( p != NULL ) {
288 char* sectionName = new char[18]; // alloc new string, pass ownership to File()
289 strcpy(sectionName, "__dof_");
290 strlcpy(&sectionName[6], providerName, 10);
291 // create unique section name so each DOF is in its own section
292 if ( sectionNamesUsed.count(sectionName) != 0 ) {
293 sectionName[15] = '0';
294 sectionName[16] = '\0';
295 while ( sectionNamesUsed.count(sectionName) != 0 ) {
296 ++sectionName[15];
299 sectionNamesUsed.insert(sectionName);
300 char symbolName[strlen(providerName)+64];
301 sprintf(symbolName, "__dtrace_dof_for_provider_%s", providerName);
302 File* f = new File("__TEXT", sectionName, "dtrace", p, dofSectionSize, ld::File::Ordinal::NullOrdinal(), symbolName);
303 if ( log ) {
304 fprintf(stderr, "libdtrace created DOF of size %ld\n", dofSectionSize);
306 // add references
307 f->reserveFixups(3*probeCount);
308 for (uint32_t i=0; i < probeCount; ++i) {
309 uint64_t offset = offsetsInDOF[i];
310 //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
311 if ( offset > dofSectionSize )
312 throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize);
313 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, probes[i].atom));
314 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, probes[i].offset));
315 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, &f->atom()));
316 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k4of4, storeKind));
318 // insert new section
319 internal.addAtom(f->atom());
321 else {
322 throw "error creating dtrace DOF section";
331 } // namespace dtrace
332 } // namespace passes
333 } // namespace ld