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