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::kindStoreARMDtraceCallSiteNop
:
147 case ld::Fixup::kindStoreThumbDtraceCallSiteNop
:
148 probeSites
.push_back(DTraceProbeInfo(atom
, fit
->offsetInAtom
, fit
->u
.name
));
150 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear
:
151 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear
:
152 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear
:
153 isEnabledSites
.push_back(DTraceProbeInfo(atom
, fit
->offsetInAtom
, fit
->u
.name
));
155 case ld::Fixup::kindDtraceExtra
:
156 atomToDtraceTypes
[atom
].insert(fit
->u
.name
);
165 // if no probes, we're done
166 if ( (probeSites
.size() == 0) && (isEnabledSites
.size() == 0) )
169 ld::Fixup::Kind storeKind
= ld::Fixup::kindNone
;
170 switch ( opts
.architecture() ) {
172 case CPU_TYPE_X86_64
:
174 storeKind
= ld::Fixup::kindStoreLittleEndian32
;
177 throw "unsupported arch for DOF";
180 // partition probes by provider name
181 // The symbol names looks like:
182 // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
183 // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
184 ProviderToProbes providerToProbes
;
185 std::vector
<DTraceProbeInfo
> emptyList
;
186 for(std::vector
<DTraceProbeInfo
>::iterator it
= probeSites
.begin(); it
!= probeSites
.end(); ++it
) {
187 // ignore probes in functions that were coalesed away rdar://problem/5628149
188 if ( it
->atom
->coalescedAway() )
190 const char* providerStart
= &it
->probeName
[16];
191 const char* providerEnd
= strchr(providerStart
, '$');
192 if ( providerEnd
!= NULL
) {
193 char providerName
[providerEnd
-providerStart
+1];
194 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
195 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
196 if ( pos
== providerToProbes
.end() ) {
197 const char* dup
= strdup(providerName
);
198 providerToProbes
[dup
] = emptyList
;
200 providerToProbes
[providerName
].push_back(*it
);
203 for(std::vector
<DTraceProbeInfo
>::iterator it
= isEnabledSites
.begin(); it
!= isEnabledSites
.end(); ++it
) {
204 // ignore probes in functions that were coalesed away rdar://problem/5628149
205 if ( it
->atom
->coalescedAway() )
207 const char* providerStart
= &it
->probeName
[20];
208 const char* providerEnd
= strchr(providerStart
, '$');
209 if ( providerEnd
!= NULL
) {
210 char providerName
[providerEnd
-providerStart
+1];
211 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
212 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
213 if ( pos
== providerToProbes
.end() ) {
214 const char* dup
= strdup(providerName
);
215 providerToProbes
[dup
] = emptyList
;
217 providerToProbes
[providerName
].push_back(*it
);
221 // create a DOF section for each provider
223 CStringSet sectionNamesUsed
;
224 for(ProviderToProbes::iterator pit
= providerToProbes
.begin(); pit
!= providerToProbes
.end(); ++pit
, ++dofIndex
) {
225 const char* providerName
= pit
->first
;
226 const std::vector
<DTraceProbeInfo
>& probes
= pit
->second
;
228 // open library and find dtrace_create_dof()
229 void* handle
= dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY
);
230 if ( handle
== NULL
)
231 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
232 createdof_func_t pCreateDOF
= (createdof_func_t
)dlsym(handle
, "dtrace_ld_create_dof");
233 if ( pCreateDOF
== NULL
)
234 throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
235 // build list of typedefs/stability infos for this provider
237 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
238 std::map
<const ld::Atom
*,CStringSet
>::iterator pos
= atomToDtraceTypes
.find(it
->atom
);
239 if ( pos
!= atomToDtraceTypes
.end() ) {
240 for(CStringSet::iterator sit
= pos
->second
.begin(); sit
!= pos
->second
.end(); ++sit
) {
241 const char* providerStart
= strchr(*sit
, '$')+1;
242 const char* providerEnd
= strchr(providerStart
, '$');
243 if ( providerEnd
!= NULL
) {
244 char aProviderName
[providerEnd
-providerStart
+1];
245 strlcpy(aProviderName
, providerStart
, providerEnd
-providerStart
+1);
246 if ( strcmp(aProviderName
, providerName
) == 0 )
252 int typeCount
= types
.size();
253 const char* typeNames
[typeCount
];
254 //fprintf(stderr, "types for %s:\n", providerName);
256 for(CStringSet::iterator it
= types
.begin(); it
!= types
.end(); ++it
) {
257 typeNames
[index
] = *it
;
258 //fprintf(stderr, "\t%s\n", *it);
262 // build list of probe/isenabled sites
263 const uint32_t probeCount
= probes
.size();
264 const char* probeNames
[probeCount
];
265 const char* funtionNames
[probeCount
];
266 uint64_t offsetsInDOF
[probeCount
];
268 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
269 probeNames
[index
] = it
->probeName
;
270 funtionNames
[index
] = it
->atom
->name();
271 offsetsInDOF
[index
] = 0;
275 fprintf(stderr
, "calling libtrace to create DOF:\n");
276 fprintf(stderr
, " types::\n");
277 for(int i
=0; i
< typeCount
; ++i
)
278 fprintf(stderr
, " [%u]\t %s\n", i
, typeNames
[i
]);
279 fprintf(stderr
, " probes::\n");
280 for(uint32_t i
=0; i
< probeCount
; ++i
)
281 fprintf(stderr
, " [%u]\t %s in %s\n", i
, probeNames
[i
], funtionNames
[i
]);
284 // call dtrace library to create DOF section
285 size_t dofSectionSize
;
286 uint8_t* p
= (*pCreateDOF
)(opts
.architecture(), typeCount
, typeNames
, probeCount
, probeNames
, funtionNames
, offsetsInDOF
, &dofSectionSize
);
288 char* sectionName
= new char[18]; // alloc new string, pass ownership to File()
289 strcpy(sectionName
, "__dof_");
290 strlcpy(§ionName
[6], providerName
, 10);
291 // create unique section name so each DOF is in its own section
292 if ( sectionNamesUsed
.count(sectionName
) != 0 ) {
293 sectionName
[15] = '0';
294 sectionName
[16] = '\0';
295 while ( sectionNamesUsed
.count(sectionName
) != 0 ) {
299 sectionNamesUsed
.insert(sectionName
);
300 char symbolName
[strlen(providerName
)+64];
301 sprintf(symbolName
, "__dtrace_dof_for_provider_%s", providerName
);
302 File
* f
= new File("__TEXT", sectionName
, "dtrace", p
, dofSectionSize
, 0, symbolName
);
304 fprintf(stderr
, "libdtrace created DOF of size %ld\n", dofSectionSize
);
307 f
->reserveFixups(3*probeCount
);
308 for (uint32_t i
=0; i
< probeCount
; ++i
) {
309 uint64_t offset
= offsetsInDOF
[i
];
310 //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
311 if ( offset
> dofSectionSize
)
312 throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i
, offset
, dofSectionSize
);
313 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k1of4
, ld::Fixup::kindSetTargetAddress
, probes
[i
].atom
));
314 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k2of4
, ld::Fixup::kindAddAddend
, probes
[i
].offset
));
315 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k3of4
, ld::Fixup::kindSubtractTargetAddress
, &f
->atom()));
316 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k4of4
, storeKind
));
318 // insert new section
319 internal
.addAtom(f
->atom());
322 throw "error creating dtrace DOF section";
331 } // namespace dtrace
332 } // namespace passes