]> git.saurik.com Git - apple/ld64.git/blob - src/ld/passes/dtrace_dof.cpp
ld64-123.2.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 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()]; }
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, uint32_t ord,
81 const char* symbolName="dof")
82 : ld::File(pth, 0, ord),
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 class CStringEquals
109 {
110 public:
111 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
112 };
113
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;
119 };
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;
122
123
124
125 void doPass(const Options& opts, ld::Internal& internal)
126 {
127 static bool log = false;
128
129 // only make __dof section in final linked images
130 if ( opts.outputKind() == Options::kObjectFile )
131 return;
132
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::kindStorePPCDtraceCallSiteNop:
147 case ld::Fixup::kindStoreARMDtraceCallSiteNop:
148 case ld::Fixup::kindStoreThumbDtraceCallSiteNop:
149 probeSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
150 break;
151 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear:
152 case ld::Fixup::kindStorePPCDtraceIsEnableSiteClear:
153 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear:
154 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
155 isEnabledSites.push_back(DTraceProbeInfo(atom, fit->offsetInAtom, fit->u.name));
156 break;
157 case ld::Fixup::kindDtraceExtra:
158 atomToDtraceTypes[atom].insert(fit->u.name);
159 break;
160 default:
161 break;
162 }
163 }
164 }
165 }
166
167 // if no probes, we're done
168 if ( (probeSites.size() == 0) && (isEnabledSites.size() == 0) )
169 return;
170
171 ld::Fixup::Kind storeKind = ld::Fixup::kindNone;
172 switch ( opts.architecture() ) {
173 case CPU_TYPE_POWERPC:
174 case CPU_TYPE_POWERPC64:
175 storeKind = ld::Fixup::kindStoreBigEndian32;
176 break;
177 case CPU_TYPE_I386:
178 case CPU_TYPE_X86_64:
179 case CPU_TYPE_ARM:
180 storeKind = ld::Fixup::kindStoreLittleEndian32;
181 break;
182 default:
183 throw "unsupported arch for DOF";
184 }
185
186 // partition probes by provider name
187 // The symbol names looks like:
188 // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
189 // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
190 ProviderToProbes providerToProbes;
191 std::vector<DTraceProbeInfo> emptyList;
192 for(std::vector<DTraceProbeInfo>::iterator it = probeSites.begin(); it != probeSites.end(); ++it) {
193 // ignore probes in functions that were coalesed away rdar://problem/5628149
194 if ( it->atom->coalescedAway() )
195 continue;
196 const char* providerStart = &it->probeName[16];
197 const char* providerEnd = strchr(providerStart, '$');
198 if ( providerEnd != NULL ) {
199 char providerName[providerEnd-providerStart+1];
200 strlcpy(providerName, providerStart, providerEnd-providerStart+1);
201 ProviderToProbes::iterator pos = providerToProbes.find(providerName);
202 if ( pos == providerToProbes.end() ) {
203 const char* dup = strdup(providerName);
204 providerToProbes[dup] = emptyList;
205 }
206 providerToProbes[providerName].push_back(*it);
207 }
208 }
209 for(std::vector<DTraceProbeInfo>::iterator it = isEnabledSites.begin(); it != isEnabledSites.end(); ++it) {
210 // ignore probes in functions that were coalesed away rdar://problem/5628149
211 if ( it->atom->coalescedAway() )
212 continue;
213 const char* providerStart = &it->probeName[20];
214 const char* providerEnd = strchr(providerStart, '$');
215 if ( providerEnd != NULL ) {
216 char providerName[providerEnd-providerStart+1];
217 strlcpy(providerName, providerStart, providerEnd-providerStart+1);
218 ProviderToProbes::iterator pos = providerToProbes.find(providerName);
219 if ( pos == providerToProbes.end() ) {
220 const char* dup = strdup(providerName);
221 providerToProbes[dup] = emptyList;
222 }
223 providerToProbes[providerName].push_back(*it);
224 }
225 }
226
227 // create a DOF section for each provider
228 int dofIndex=1;
229 CStringSet sectionNamesUsed;
230 for(ProviderToProbes::iterator pit = providerToProbes.begin(); pit != providerToProbes.end(); ++pit, ++dofIndex) {
231 const char* providerName = pit->first;
232 const std::vector<DTraceProbeInfo>& probes = pit->second;
233
234 // open library and find dtrace_create_dof()
235 void* handle = dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY);
236 if ( handle == NULL )
237 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
238 createdof_func_t pCreateDOF = (createdof_func_t)dlsym(handle, "dtrace_ld_create_dof");
239 if ( pCreateDOF == NULL )
240 throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
241 // build list of typedefs/stability infos for this provider
242 CStringSet types;
243 for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
244 std::map<const ld::Atom*,CStringSet>::iterator pos = atomToDtraceTypes.find(it->atom);
245 if ( pos != atomToDtraceTypes.end() ) {
246 for(CStringSet::iterator sit = pos->second.begin(); sit != pos->second.end(); ++sit) {
247 const char* providerStart = strchr(*sit, '$')+1;
248 const char* providerEnd = strchr(providerStart, '$');
249 if ( providerEnd != NULL ) {
250 char aProviderName[providerEnd-providerStart+1];
251 strlcpy(aProviderName, providerStart, providerEnd-providerStart+1);
252 if ( strcmp(aProviderName, providerName) == 0 )
253 types.insert(*sit);
254 }
255 }
256 }
257 }
258 int typeCount = types.size();
259 const char* typeNames[typeCount];
260 //fprintf(stderr, "types for %s:\n", providerName);
261 uint32_t index = 0;
262 for(CStringSet::iterator it = types.begin(); it != types.end(); ++it) {
263 typeNames[index] = *it;
264 //fprintf(stderr, "\t%s\n", *it);
265 ++index;
266 }
267
268 // build list of probe/isenabled sites
269 const uint32_t probeCount = probes.size();
270 const char* probeNames[probeCount];
271 const char* funtionNames[probeCount];
272 uint64_t offsetsInDOF[probeCount];
273 index = 0;
274 for(std::vector<DTraceProbeInfo>::const_iterator it = probes.begin(); it != probes.end(); ++it) {
275 probeNames[index] = it->probeName;
276 funtionNames[index] = it->atom->name();
277 offsetsInDOF[index] = 0;
278 ++index;
279 }
280 if ( log ) {
281 fprintf(stderr, "calling libtrace to create DOF:\n");
282 fprintf(stderr, " types::\n");
283 for(int i=0; i < typeCount; ++i)
284 fprintf(stderr, " [%u]\t %s\n", i, typeNames[i]);
285 fprintf(stderr, " probes::\n");
286 for(uint32_t i=0; i < probeCount; ++i)
287 fprintf(stderr, " [%u]\t %s in %s\n", i, probeNames[i], funtionNames[i]);
288 }
289
290 // call dtrace library to create DOF section
291 size_t dofSectionSize;
292 uint8_t* p = (*pCreateDOF)(opts.architecture(), typeCount, typeNames, probeCount, probeNames, funtionNames, offsetsInDOF, &dofSectionSize);
293 if ( p != NULL ) {
294 char* sectionName = new char[18]; // alloc new string, pass ownership to File()
295 strcpy(sectionName, "__dof_");
296 strlcpy(&sectionName[6], providerName, 10);
297 // create unique section name so each DOF is in its own section
298 if ( sectionNamesUsed.count(sectionName) != 0 ) {
299 sectionName[15] = '0';
300 sectionName[16] = '\0';
301 while ( sectionNamesUsed.count(sectionName) != 0 ) {
302 ++sectionName[15];
303 }
304 }
305 sectionNamesUsed.insert(sectionName);
306 char symbolName[strlen(providerName)+64];
307 sprintf(symbolName, "__dtrace_dof_for_provider_%s", providerName);
308 File* f = new File("__TEXT", sectionName, "dtrace", p, dofSectionSize, 0, symbolName);
309 if ( log ) {
310 fprintf(stderr, "libdtrace created DOF of size %ld\n", dofSectionSize);
311 }
312 // add references
313 f->reserveFixups(3*probeCount);
314 for (uint32_t i=0; i < probeCount; ++i) {
315 uint64_t offset = offsetsInDOF[i];
316 //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
317 if ( offset > dofSectionSize )
318 throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i, offset, dofSectionSize);
319 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k1of4, ld::Fixup::kindSetTargetAddress, probes[i].atom));
320 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k2of4, ld::Fixup::kindAddAddend, probes[i].offset));
321 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k3of4, ld::Fixup::kindSubtractTargetAddress, &f->atom()));
322 f->addSectionFixup(ld::Fixup(offset, ld::Fixup::k4of4, storeKind));
323 }
324 // insert new section
325 internal.addAtom(f->atom());
326 }
327 else {
328 throw "error creating dtrace DOF section";
329 }
330 }
331
332
333
334 }
335
336
337 } // namespace dtrace
338 } // namespace passes
339 } // namespace ld