]> git.saurik.com Git - apple/ld64.git/blob - src/ld/passes/dtrace_dof.cpp
74328ffbe81275ec924550930d4e137b8abcff38
[apple/ld64.git] / src / ld / passes / dtrace_dof.cpp
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2009 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25
26 #include <stdint.h>
27 #include <math.h>
28 #include <unistd.h>
29 #include <dlfcn.h>
30
31 #include <vector>
32 #include <map>
33 #include <unordered_map>
34 #include <unordered_set>
35
36 #include "ld.hpp"
37 #include "dtrace_dof.h"
38
39 // prototype for entry point in libdtrace.dylib
40 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);
41
42
43 namespace ld {
44 namespace passes {
45 namespace dtrace {
46
47 class File; // forward reference
48
49 class Atom : public ld::Atom {
50 public:
51 Atom(class File& f, const char* n, const uint8_t* content, uint64_t sz);
52
53 virtual ld::File* file() const { return (ld::File*)&_file; }
54 virtual const char* name() const { return _name; }
55 virtual uint64_t size() const { return _size; }
56 virtual uint64_t objectAddress() const { return 0; }
57 virtual void copyRawContent(uint8_t buffer[]) const
58 { memcpy(buffer, _content, _size); }
59 virtual void setScope(Scope) { }
60 virtual ld::Fixup::iterator fixupsBegin() const { return &_fixups[0]; }
61 virtual ld::Fixup::iterator fixupsEnd() const { return &_fixups[_fixups.size()]; }
62
63 protected:
64 friend class File;
65 virtual ~Atom() {}
66
67 class File& _file;
68 const char* _name;
69 const uint8_t* _content;
70 uint64_t _size;
71 mutable std::vector<ld::Fixup> _fixups;
72 };
73
74
75 class File : public ld::File
76 {
77 public:
78 File(const char* segmentName, const char* sectionName, const char* pth,
79 const uint8_t fileContent[], uint64_t fileLength, Ordinal ord,
80 const char* symbolName="dof")
81 : ld::File(pth, 0, ord, Other),
82 _atom(*this, symbolName, fileContent, fileLength),
83 _section(segmentName, sectionName, ld::Section::typeDtraceDOF) { }
84 virtual ~File() {}
85
86 virtual bool forEachAtom(AtomHandler& h) const { h.doAtom(_atom); return true; }
87 virtual bool justInTimeforEachAtom(const char* name, AtomHandler&) const { return false; }
88
89 void reserveFixups(unsigned int count) { _atom._fixups.reserve(count); }
90 void addSectionFixup(const ld::Fixup& f) { _atom._fixups.push_back(f); }
91 ld::Atom& atom() { return _atom; }
92 private:
93 friend class Atom;
94
95 Atom _atom;
96 ld::Section _section;
97 };
98
99 Atom::Atom(File& f, const char* n, const uint8_t* content, uint64_t sz)
100 : ld::Atom(f._section, ld::Atom::definitionRegular, ld::Atom::combineNever,
101 ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified,
102 symbolTableNotIn, false, false, false, ld::Atom::Alignment(0)),
103 _file(f), _name(strdup(n)), _content(content), _size(sz) {}
104
105
106
107 struct DTraceProbeInfo {
108 DTraceProbeInfo(const ld::Atom* a, uint32_t o, const char* n) : atom(a), offset(o), probeName(n) {}
109 const ld::Atom* atom;
110 uint32_t offset;
111 const char* probeName;
112 };
113 typedef std::unordered_map<const char*, std::vector<DTraceProbeInfo>, CStringHash, CStringEquals> ProviderToProbes;
114 typedef std::unordered_set<const char*, CStringHash, CStringEquals> CStringSet;
115
116
117
118 void doPass(const Options& opts, ld::Internal& internal)
119 {
120 static bool log = false;
121
122 // only make __dof section in final linked images
123 if ( opts.outputKind() == Options::kObjectFile )
124 return;
125
126 // scan all atoms looking for dtrace probes
127 std::vector<DTraceProbeInfo> probeSites;
128 std::vector<DTraceProbeInfo> isEnabledSites;
129 std::map<const ld::Atom*,CStringSet> atomToDtraceTypes;
130 for (std::vector<ld::Internal::FinalSection*>::iterator sit=internal.sections.begin(); sit != internal.sections.end(); ++sit) {
131 ld::Internal::FinalSection* sect = *sit;
132 if ( sect->type() != ld::Section::typeCode )
133 continue;
134 for (std::vector<const ld::Atom*>::iterator ait=sect->atoms.begin(); ait != sect->atoms.end(); ++ait) {
135 const ld::Atom* atom = *ait;
136 for (ld::Fixup::iterator fit = atom->fixupsBegin(), end=atom->fixupsEnd(); fit != end; ++fit) {
137 switch ( fit->kind ) {
138 case ld::Fixup::kindStoreX86DtraceCallSiteNop:
139 case ld::Fixup::kindStoreARMDtraceCallSiteNop:
140 case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
141 probeSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
142 break;
143 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
144 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
145 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
146 isEnabledSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
147 break;
148 case ld::Fixup::kindDtraceExtra:
149 atomToDtraceTypes[atom].insert(fit->u.name);
150 break;
151 default:
152 break;
153 }
154 }
155 }
156 }
157
158 // if no probes, we're done
159 if ( (probeSites.size() == 0) && (isEnabledSites.size() == 0) )
160 return;
161
162 ld::Fixup::Kind storeKind = ld::Fixup::kindNone;
163 switch ( opts.architecture() ) {
164 case CPU_TYPE_I386:
165 case CPU_TYPE_X86_64:
166 case CPU_TYPE_ARM:
167 storeKind = ld::Fixup::kindStoreLittleEndian32;
168 break;
169 default:
170 throw "unsupported arch for DOF";
171 }
172
173 // partition probes by provider name
174 // The symbol names looks like:
175 // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
176 // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
177 ProviderToProbes providerToProbes;
178 std::vector<DTraceProbeInfo> emptyList;
179 for(std::vector<DTraceProbeInfo>::iterator it = probeSites.begin(); it != probeSites.end(); ++it) {
180 // ignore probes in functions that were coalesed away rdar://problem/5628149
181 if ( it->atom->coalescedAway() )
182 continue;
183 const char* providerStart = &it->probeName[16];
184 const char* providerEnd = strchr(providerStart, '$');
185 if ( providerEnd != NULL ) {
186 char providerName[providerEnd-providerStart+1];
187 strlcpy(providerName, providerStart, providerEnd-providerStart+1);
188 ProviderToProbes::iterator pos = providerToProbes.find(providerName);
189 if ( pos == providerToProbes.end() ) {
190 const char* dup = strdup(providerName);
191 providerToProbes[dup] = emptyList;
192 }
193 providerToProbes[providerName].push_back(*it);
194 }
195 }
196 for(std::vector<DTraceProbeInfo>::iterator it = isEnabledSites.begin(); it != isEnabledSites.end(); ++it) {
197 // ignore probes in functions that were coalesed away rdar://problem/5628149
198 if ( it->atom->coalescedAway() )
199 continue;
200 const char* providerStart = &it->probeName[20];
201 const char* providerEnd = strchr(providerStart, '$');
202 if ( providerEnd != NULL ) {
203 char providerName[providerEnd-providerStart+1];
204 strlcpy(providerName, providerStart, providerEnd-providerStart+1);
205 ProviderToProbes::iterator pos = providerToProbes.find(providerName);
206 if ( pos == providerToProbes.end() ) {
207 const char* dup = strdup(providerName);
208 providerToProbes[dup] = emptyList;
209 }
210 providerToProbes[providerName].push_back(*it);
211 }
212 }
213
214 // create a DOF section for each provider
215 int dofIndex=1;
216 CStringSet sectionNamesUsed;
217 for(ProviderToProbes::iterator pit = providerToProbes.begin(); pit != providerToProbes.end(); ++pit, ++dofIndex) {
218 const char* providerName = pit->first;
219 const std::vector<DTraceProbeInfo>& probes = pit->second;
220
221 // open library and find dtrace_create_dof()
222 void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY);
223 if ( handle == NULL )
224 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
225 createdof_func_t pCreateDOF = (createdof_func_t)dlsym(handle, "dtrace_ld_create_dof");
226 if ( pCreateDOF == NULL )
227 throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
228 // build list of typedefs/stability infos for this provider
229 CStringSet types;
230 for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
231 std::map<const ld::Atom*,CStringSet>::iterator pos = atomToDtraceTypes.find(it->atom);
232 if ( pos != atomToDtraceTypes.end() ) {
233 for(CStringSet::iterator sit = pos->second.begin(); sit != pos->second.end(); ++sit) {
234 const char* providerStart = strchr(*sit, '$')+1;
235 const char* providerEnd = strchr(providerStart, '$');
236 if ( providerEnd != NULL ) {
237 char aProviderName[providerEnd-providerStart+1];
238 strlcpy(aProviderName, providerStart, providerEnd-providerStart+1);
239 if ( strcmp(aProviderName, providerName) == 0 )
240 types.insert(*sit);
241 }
242 }
243 }
244 }
245 int typeCount = types.size();
246 const char* typeNames[typeCount];
247 //fprintf(stderr, "types for %s:\n", providerName);
248 uint32_t index = 0;
249 for(CStringSet::iterator it = types.begin(); it != types.end(); ++it) {
250 typeNames[index] = *it;
251 //fprintf(stderr, "\t%s\n", *it);
252 ++index;
253 }
254
255 // build list of probe/isenabled sites
256 const uint32_t probeCount = probes.size();
257 const char* probeNames[probeCount];
258 const char* funtionNames[probeCount];
259 uint64_t offsetsInDOF[probeCount];
260 index = 0;
261 for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
262 probeNames[index] = it->probeName;
263 funtionNames[index] = it->atom->name();
264 offsetsInDOF[index] = 0;
265 ++index;
266 }
267 if ( log ) {
268 fprintf(stderr, "calling libtrace to create DOF:\n");
269 fprintf(stderr, " types::\n");
270 for(int i=0; i < typeCount; ++i)
271 fprintf(stderr, " [%u]\t %s\n", i, typeNames[i]);
272 fprintf(stderr, " probes::\n");
273 for(uint32_t i=0; i < probeCount; ++i)
274 fprintf(stderr, " [%u]\t %s in %s\n", i, probeNames[i], funtionNames[i]);
275 }
276
277 // call dtrace library to create DOF section
278 size_t dofSectionSize;
279 uint8_t* p = (*pCreateDOF)(opts.architecture(), typeCount, typeNames, probeCount, probeNames, funtionNames, offsetsInDOF, &dofSectionSize);
280 if ( p != NULL ) {
281 char* sectionName = new char[18]; // alloc new string, pass ownership to File()
282 strcpy(sectionName, "__dof_");
283 strlcpy(&sectionName[6], providerName, 10);
284 // create unique section name so each DOF is in its own section
285 if ( sectionNamesUsed.count(sectionName) != 0 ) {
286 sectionName[15] = '0';
287 sectionName[16] = '\0';
288 while ( sectionNamesUsed.count(sectionName) != 0 ) {
289 ++sectionName[15];
290 }
291 }
292 sectionNamesUsed.insert(sectionName);
293 char symbolName[strlen(providerName)+64];
294 sprintf(symbolName, "__dtrace_dof_for_provider_%s", providerName);
295 File* f = new File("__TEXT", sectionName, "dtrace", p, dofSectionSize, ld::File::Ordinal::NullOrdinal(), symbolName);
296 if ( log ) {
297 fprintf(stderr, "libdtrace created DOF of size %ld\n", dofSectionSize);
298 }
299 // add references
300 f->reserveFixups(3*probeCount);
301 for (uint32_t i=0; i < probeCount; ++i) {
302 uint64_t offset = offsetsInDOF[i];
303 //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
304 if ( offset > dofSectionSize )
305 throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize);
306 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, probes[i].atom));
307 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, probes[i].offset));
308 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, &f->atom()));
309 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k4of4, storeKind));
310 }
311 // insert new section
312 internal.addAtom(f->atom());
313 }
314 else {
315 throw "error creating dtrace DOF section";
316 }
317 }
318
319
320
321 }
322
323
324 } // namespace dtrace
325 } // namespace passes
326 } // namespace ld