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