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
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@
33 #include <ext/hash_map>
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
);
46 class File
; // forward reference
48 class Atom
: public ld::Atom
{
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
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()]; }
70 const uint8_t* _content
;
72 mutable std::vector
<ld::Fixup
> _fixups
;
76 class File
: public ld::File
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
) { }
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
; }
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
) {}
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
;
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
)
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
)
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
));
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
));
157 case ld::Fixup::kindDtraceExtra
:
158 atomToDtraceTypes
[atom
].insert(fit
->u
.name
);
167 // if no probes, we're done
168 if ( (probeSites
.size() == 0) && (isEnabledSites
.size() == 0) )
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
;
178 case CPU_TYPE_X86_64
:
180 storeKind
= ld::Fixup::kindStoreLittleEndian32
;
183 throw "unsupported arch for DOF";
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() )
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
;
206 providerToProbes
[providerName
].push_back(*it
);
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() )
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
;
223 providerToProbes
[providerName
].push_back(*it
);
227 // create a DOF section for each provider
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
;
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
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 )
258 int typeCount
= types
.size();
259 const char* typeNames
[typeCount
];
260 //fprintf(stderr, "types for %s:\n", providerName);
262 for(CStringSet::iterator it
= types
.begin(); it
!= types
.end(); ++it
) {
263 typeNames
[index
] = *it
;
264 //fprintf(stderr, "\t%s\n", *it);
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
];
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;
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
]);
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
);
294 char* sectionName
= new char[18]; // alloc new string, pass ownership to File()
295 strcpy(sectionName
, "__dof_");
296 strlcpy(§ionName
[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 ) {
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
);
310 fprintf(stderr
, "libdtrace created DOF of size %ld\n", dofSectionSize
);
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
));
324 // insert new section
325 internal
.addAtom(f
->atom());
328 throw "error creating dtrace DOF section";
337 } // namespace dtrace
338 } // namespace passes