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 <unordered_map>
34 #include <unordered_set>
37 #include "dtrace_dof.h"
39 // prototype for entry point in libdtrace.dylib
40 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
);
47 class File
; // forward reference
49 class Atom
: public ld::Atom
{
51 Atom(class File
& f
, const char* n
, const uint8_t* content
, uint64_t sz
);
53 virtual ld::File
* file() const { return (ld::File
*)&_file
; }
54 virtual const char* name() const { return _name
; }
55 virtual uint64_t size() const { return _size
; }
56 virtual uint64_t objectAddress() const { return 0; }
57 virtual void copyRawContent(uint8_t buffer
[]) const
58 { memcpy(buffer
, _content
, _size
); }
59 virtual void setScope(Scope
) { }
60 virtual ld::Fixup::iterator
fixupsBegin() const { return &_fixups
[0]; }
61 virtual ld::Fixup::iterator
fixupsEnd() const { return &_fixups
[_fixups
.size()]; }
69 const uint8_t* _content
;
71 mutable std::vector
<ld::Fixup
> _fixups
;
75 class File
: public ld::File
78 File(const char* segmentName
, const char* sectionName
, const char* pth
,
79 const uint8_t fileContent
[], uint64_t fileLength
, Ordinal ord
,
80 const char* symbolName
="dof")
81 : ld::File(pth
, 0, ord
, Other
),
82 _atom(*this, symbolName
, fileContent
, fileLength
),
83 _section(segmentName
, sectionName
, ld::Section::typeDtraceDOF
) { }
86 virtual bool forEachAtom(AtomHandler
& h
) const { h
.doAtom(_atom
); return true; }
87 virtual bool justInTimeforEachAtom(const char* name
, AtomHandler
&) const { return false; }
89 void reserveFixups(unsigned int count
) { _atom
._fixups
.reserve(count
); }
90 void addSectionFixup(const ld::Fixup
& f
) { _atom
._fixups
.push_back(f
); }
91 ld::Atom
& atom() { return _atom
; }
99 Atom::Atom(File
& f
, const char* n
, const uint8_t* content
, uint64_t sz
)
100 : ld::Atom(f
._section
, ld::Atom::definitionRegular
, ld::Atom::combineNever
,
101 ld::Atom::scopeTranslationUnit
, ld::Atom::typeUnclassified
,
102 symbolTableNotIn
, false, false, false, ld::Atom::Alignment(0)),
103 _file(f
), _name(strdup(n
)), _content(content
), _size(sz
) {}
107 struct DTraceProbeInfo
{
108 DTraceProbeInfo(const ld::Atom
* a
, uint32_t o
, const char* n
) : atom(a
), offset(o
), probeName(n
) {}
109 const ld::Atom
* atom
;
111 const char* probeName
;
113 typedef std::unordered_map
<const char*, std::vector
<DTraceProbeInfo
>, CStringHash
, CStringEquals
> ProviderToProbes
;
114 typedef std::unordered_set
<const char*, CStringHash
, CStringEquals
> CStringSet
;
118 void doPass(const Options
& opts
, ld::Internal
& internal
)
120 static bool log
= false;
122 // only make __dof section in final linked images
123 if ( opts
.outputKind() == Options::kObjectFile
)
126 // scan all atoms looking for dtrace probes
127 std::vector
<DTraceProbeInfo
> probeSites
;
128 std::vector
<DTraceProbeInfo
> isEnabledSites
;
129 std::map
<const ld::Atom
*,CStringSet
> atomToDtraceTypes
;
130 for (std::vector
<ld::Internal::FinalSection
*>::iterator sit
=internal
.sections
.begin(); sit
!= internal
.sections
.end(); ++sit
) {
131 ld::Internal::FinalSection
* sect
= *sit
;
132 if ( sect
->type() != ld::Section::typeCode
)
134 for (std::vector
<const ld::Atom
*>::iterator ait
=sect
->atoms
.begin(); ait
!= sect
->atoms
.end(); ++ait
) {
135 const ld::Atom
* atom
= *ait
;
136 for (ld::Fixup::iterator fit
= atom
->fixupsBegin(), end
=atom
->fixupsEnd(); fit
!= end
; ++fit
) {
137 switch ( fit
->kind
) {
138 case ld::Fixup::kindStoreX86DtraceCallSiteNop
:
139 case ld::Fixup::kindStoreARMDtraceCallSiteNop
:
140 case ld::Fixup::kindStoreThumbDtraceCallSiteNop
:
141 probeSites
.push_back(DTraceProbeInfo(atom
, fit
->offsetInAtom
, fit
->u
.name
));
143 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear
:
144 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear
:
145 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear
:
146 isEnabledSites
.push_back(DTraceProbeInfo(atom
, fit
->offsetInAtom
, fit
->u
.name
));
148 case ld::Fixup::kindDtraceExtra
:
149 atomToDtraceTypes
[atom
].insert(fit
->u
.name
);
158 // if no probes, we're done
159 if ( (probeSites
.size() == 0) && (isEnabledSites
.size() == 0) )
162 ld::Fixup::Kind storeKind
= ld::Fixup::kindNone
;
163 switch ( opts
.architecture() ) {
165 case CPU_TYPE_X86_64
:
167 storeKind
= ld::Fixup::kindStoreLittleEndian32
;
170 throw "unsupported arch for DOF";
173 // partition probes by provider name
174 // The symbol names looks like:
175 // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
176 // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
177 ProviderToProbes providerToProbes
;
178 std::vector
<DTraceProbeInfo
> emptyList
;
179 for(std::vector
<DTraceProbeInfo
>::iterator it
= probeSites
.begin(); it
!= probeSites
.end(); ++it
) {
180 // ignore probes in functions that were coalesed away rdar://problem/5628149
181 if ( it
->atom
->coalescedAway() )
183 const char* providerStart
= &it
->probeName
[16];
184 const char* providerEnd
= strchr(providerStart
, '$');
185 if ( providerEnd
!= NULL
) {
186 char providerName
[providerEnd
-providerStart
+1];
187 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
188 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
189 if ( pos
== providerToProbes
.end() ) {
190 const char* dup
= strdup(providerName
);
191 providerToProbes
[dup
] = emptyList
;
193 providerToProbes
[providerName
].push_back(*it
);
196 for(std::vector
<DTraceProbeInfo
>::iterator it
= isEnabledSites
.begin(); it
!= isEnabledSites
.end(); ++it
) {
197 // ignore probes in functions that were coalesed away rdar://problem/5628149
198 if ( it
->atom
->coalescedAway() )
200 const char* providerStart
= &it
->probeName
[20];
201 const char* providerEnd
= strchr(providerStart
, '$');
202 if ( providerEnd
!= NULL
) {
203 char providerName
[providerEnd
-providerStart
+1];
204 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
205 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
206 if ( pos
== providerToProbes
.end() ) {
207 const char* dup
= strdup(providerName
);
208 providerToProbes
[dup
] = emptyList
;
210 providerToProbes
[providerName
].push_back(*it
);
214 // create a DOF section for each provider
216 CStringSet sectionNamesUsed
;
217 for(ProviderToProbes::iterator pit
= providerToProbes
.begin(); pit
!= providerToProbes
.end(); ++pit
, ++dofIndex
) {
218 const char* providerName
= pit
->first
;
219 const std::vector
<DTraceProbeInfo
>& probes
= pit
->second
;
221 // open library and find dtrace_create_dof()
222 void* handle
= dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY
);
223 if ( handle
== NULL
)
224 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
225 createdof_func_t pCreateDOF
= (createdof_func_t
)dlsym(handle
, "dtrace_ld_create_dof");
226 if ( pCreateDOF
== NULL
)
227 throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
228 // build list of typedefs/stability infos for this provider
230 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
231 std::map
<const ld::Atom
*,CStringSet
>::iterator pos
= atomToDtraceTypes
.find(it
->atom
);
232 if ( pos
!= atomToDtraceTypes
.end() ) {
233 for(CStringSet::iterator sit
= pos
->second
.begin(); sit
!= pos
->second
.end(); ++sit
) {
234 const char* providerStart
= strchr(*sit
, '$')+1;
235 const char* providerEnd
= strchr(providerStart
, '$');
236 if ( providerEnd
!= NULL
) {
237 char aProviderName
[providerEnd
-providerStart
+1];
238 strlcpy(aProviderName
, providerStart
, providerEnd
-providerStart
+1);
239 if ( strcmp(aProviderName
, providerName
) == 0 )
245 int typeCount
= types
.size();
246 const char* typeNames
[typeCount
];
247 //fprintf(stderr, "types for %s:\n", providerName);
249 for(CStringSet::iterator it
= types
.begin(); it
!= types
.end(); ++it
) {
250 typeNames
[index
] = *it
;
251 //fprintf(stderr, "\t%s\n", *it);
255 // build list of probe/isenabled sites
256 const uint32_t probeCount
= probes
.size();
257 const char* probeNames
[probeCount
];
258 const char* funtionNames
[probeCount
];
259 uint64_t offsetsInDOF
[probeCount
];
261 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
262 probeNames
[index
] = it
->probeName
;
263 funtionNames
[index
] = it
->atom
->name();
264 offsetsInDOF
[index
] = 0;
268 fprintf(stderr
, "calling libtrace to create DOF:\n");
269 fprintf(stderr
, " types::\n");
270 for(int i
=0; i
< typeCount
; ++i
)
271 fprintf(stderr
, " [%u]\t %s\n", i
, typeNames
[i
]);
272 fprintf(stderr
, " probes::\n");
273 for(uint32_t i
=0; i
< probeCount
; ++i
)
274 fprintf(stderr
, " [%u]\t %s in %s\n", i
, probeNames
[i
], funtionNames
[i
]);
277 // call dtrace library to create DOF section
278 size_t dofSectionSize
;
279 uint8_t* p
= (*pCreateDOF
)(opts
.architecture(), typeCount
, typeNames
, probeCount
, probeNames
, funtionNames
, offsetsInDOF
, &dofSectionSize
);
281 char* sectionName
= new char[18]; // alloc new string, pass ownership to File()
282 strcpy(sectionName
, "__dof_");
283 strlcpy(§ionName
[6], providerName
, 10);
284 // create unique section name so each DOF is in its own section
285 if ( sectionNamesUsed
.count(sectionName
) != 0 ) {
286 sectionName
[15] = '0';
287 sectionName
[16] = '\0';
288 while ( sectionNamesUsed
.count(sectionName
) != 0 ) {
292 sectionNamesUsed
.insert(sectionName
);
293 char symbolName
[strlen(providerName
)+64];
294 sprintf(symbolName
, "__dtrace_dof_for_provider_%s", providerName
);
295 File
* f
= new File("__TEXT", sectionName
, "dtrace", p
, dofSectionSize
, ld::File::Ordinal::NullOrdinal(), symbolName
);
297 fprintf(stderr
, "libdtrace created DOF of size %ld\n", dofSectionSize
);
300 f
->reserveFixups(3*probeCount
);
301 for (uint32_t i
=0; i
< probeCount
; ++i
) {
302 uint64_t offset
= offsetsInDOF
[i
];
303 //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
304 if ( offset
> dofSectionSize
)
305 throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i
, offset
, dofSectionSize
);
306 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k1of4
, ld::Fixup::kindSetTargetAddress
, probes
[i
].atom
));
307 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k2of4
, ld::Fixup::kindAddAddend
, probes
[i
].offset
));
308 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k3of4
, ld::Fixup::kindSubtractTargetAddress
, &f
->atom()));
309 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k4of4
, storeKind
));
311 // insert new section
312 internal
.addAtom(f
->atom());
315 throw "error creating dtrace DOF section";
324 } // namespace dtrace
325 } // namespace passes