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 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()]; }
68 const uint8_t* _content
;
70 mutable std::vector
<ld::Fixup
> _fixups
;
74 class File
: public ld::File
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
) { }
85 virtual bool forEachAtom(AtomHandler
& h
) const { h
.doAtom(_atom
); return true; }
86 virtual bool justInTimeforEachAtom(const char* name
, AtomHandler
&) const { return false; }
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
; }
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
) {}
109 bool operator()(const char* left
, const char* right
) const { return (strcmp(left
, right
) == 0); }
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
;
116 const char* probeName
;
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
;
123 void doPass(const Options
& opts
, ld::Internal
& internal
)
125 static bool log
= false;
127 // only make __dof section in final linked images
128 if ( opts
.outputKind() == Options::kObjectFile
)
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
)
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
));
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
));
153 case ld::Fixup::kindDtraceExtra
:
154 atomToDtraceTypes
[atom
].insert(fit
->u
.name
);
163 // if no probes, we're done
164 if ( (probeSites
.size() == 0) && (isEnabledSites
.size() == 0) )
167 ld::Fixup::Kind storeKind
= ld::Fixup::kindNone
;
168 switch ( opts
.architecture() ) {
170 case CPU_TYPE_X86_64
:
172 storeKind
= ld::Fixup::kindStoreLittleEndian32
;
175 throw "unsupported arch for DOF";
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() )
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
;
198 providerToProbes
[providerName
].push_back(*it
);
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() )
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
;
215 providerToProbes
[providerName
].push_back(*it
);
219 // create a DOF section for each provider
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
;
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
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 )
250 int typeCount
= types
.size();
251 const char* typeNames
[typeCount
];
252 //fprintf(stderr, "types for %s:\n", providerName);
254 for(CStringSet::iterator it
= types
.begin(); it
!= types
.end(); ++it
) {
255 typeNames
[index
] = *it
;
256 //fprintf(stderr, "\t%s\n", *it);
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
];
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;
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
]);
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
);
286 char* sectionName
= new char[18]; // alloc new string, pass ownership to File()
287 strcpy(sectionName
, "__dof_");
288 strlcpy(§ionName
[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 ) {
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
);
302 fprintf(stderr
, "libdtrace created DOF of size %ld\n", dofSectionSize
);
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
));
316 // insert new section
317 internal
.addAtom(f
->atom());
320 throw "error creating dtrace DOF section";
329 } // namespace dtrace
330 } // namespace passes