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 "MachOFileAbstraction.hpp"
38 #include "dtrace_dof.h"
40 // prototype for entry point in libdtrace.dylib
41 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
);
48 class File
; // forward reference
50 class Atom
: public ld::Atom
{
52 Atom(class File
& f
, const char* n
, const uint8_t* content
, uint64_t sz
);
54 virtual ld::File
* file() const { return (ld::File
*)&_file
; }
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
, Ordinal ord
,
81 const char* symbolName
="dof")
82 : ld::File(pth
, 0, ord
, Other
),
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
) {}
108 struct DTraceProbeInfo
{
109 DTraceProbeInfo(const ld::Atom
* a
, uint32_t o
, const char* n
) : atom(a
), offset(o
), probeName(n
) {}
110 const ld::Atom
* atom
;
112 const char* probeName
;
114 typedef std::unordered_map
<const char*, std::vector
<DTraceProbeInfo
>, CStringHash
, CStringEquals
> ProviderToProbes
;
115 typedef std::unordered_set
<const char*, CStringHash
, CStringEquals
> CStringSet
;
119 void doPass(const Options
& opts
, ld::Internal
& internal
)
121 static bool log
= false;
123 // only make __dof section in final linked images
124 if ( opts
.outputKind() == Options::kObjectFile
)
127 // skip making __dof section if command line option said not to
128 if ( ! opts
.generateDtraceDOF() )
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 case ld::Fixup::kindStoreARM64DtraceCallSiteNop
:
147 probeSites
.push_back(DTraceProbeInfo(atom
, fit
->offsetInAtom
, fit
->u
.name
));
149 case ld::Fixup::kindStoreX86DtraceIsEnableSiteClear
:
150 case ld::Fixup::kindStoreARMDtraceIsEnableSiteClear
:
151 case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear
:
152 case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear
:
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
:
175 storeKind
= ld::Fixup::kindStoreLittleEndian32
;
178 throw "unsupported arch for DOF";
181 // partition probes by provider name
182 // The symbol names looks like:
183 // "___dtrace_probe$" provider-name "$" probe-name [ "$"... ]
184 // "___dtrace_isenabled$" provider-name "$" probe-name [ "$"... ]
185 ProviderToProbes providerToProbes
;
186 std::vector
<DTraceProbeInfo
> emptyList
;
187 for(std::vector
<DTraceProbeInfo
>::iterator it
= probeSites
.begin(); it
!= probeSites
.end(); ++it
) {
188 // ignore probes in functions that were coalesed away rdar://problem/5628149
189 if ( it
->atom
->coalescedAway() )
191 const char* providerStart
= &it
->probeName
[16];
192 const char* providerEnd
= strchr(providerStart
, '$');
193 if ( providerEnd
!= NULL
) {
194 char providerName
[providerEnd
-providerStart
+1];
195 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
196 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
197 if ( pos
== providerToProbes
.end() ) {
198 const char* dup
= strdup(providerName
);
199 providerToProbes
[dup
] = emptyList
;
201 providerToProbes
[providerName
].push_back(*it
);
204 for(std::vector
<DTraceProbeInfo
>::iterator it
= isEnabledSites
.begin(); it
!= isEnabledSites
.end(); ++it
) {
205 // ignore probes in functions that were coalesed away rdar://problem/5628149
206 if ( it
->atom
->coalescedAway() )
208 const char* providerStart
= &it
->probeName
[20];
209 const char* providerEnd
= strchr(providerStart
, '$');
210 if ( providerEnd
!= NULL
) {
211 char providerName
[providerEnd
-providerStart
+1];
212 strlcpy(providerName
, providerStart
, providerEnd
-providerStart
+1);
213 ProviderToProbes::iterator pos
= providerToProbes
.find(providerName
);
214 if ( pos
== providerToProbes
.end() ) {
215 const char* dup
= strdup(providerName
);
216 providerToProbes
[dup
] = emptyList
;
218 providerToProbes
[providerName
].push_back(*it
);
222 // create a DOF section for each provider
224 CStringSet sectionNamesUsed
;
225 for(ProviderToProbes::iterator pit
= providerToProbes
.begin(); pit
!= providerToProbes
.end(); ++pit
, ++dofIndex
) {
226 const char* providerName
= pit
->first
;
227 const std::vector
<DTraceProbeInfo
>& probes
= pit
->second
;
229 // open library and find dtrace_create_dof()
230 void* handle
= dlopen("/usr/lib/libdtrace.dylib", RTLD_LAZY
);
231 if ( handle
== NULL
)
232 throwf("couldn't dlopen() /usr/lib/libdtrace.dylib: %s", dlerror());
233 createdof_func_t pCreateDOF
= (createdof_func_t
)dlsym(handle
, "dtrace_ld_create_dof");
234 if ( pCreateDOF
== NULL
)
235 throwf("couldn't find \"dtrace_ld_create_dof\" in /usr/lib/libdtrace.dylib: %s", dlerror());
236 // build list of typedefs/stability infos for this provider
238 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
239 std::map
<const ld::Atom
*,CStringSet
>::iterator pos
= atomToDtraceTypes
.find(it
->atom
);
240 if ( pos
!= atomToDtraceTypes
.end() ) {
241 for(CStringSet::iterator sit
= pos
->second
.begin(); sit
!= pos
->second
.end(); ++sit
) {
242 const char* providerStart
= strchr(*sit
, '$')+1;
243 const char* providerEnd
= strchr(providerStart
, '$');
244 if ( providerEnd
!= NULL
) {
245 char aProviderName
[providerEnd
-providerStart
+1];
246 strlcpy(aProviderName
, providerStart
, providerEnd
-providerStart
+1);
247 if ( strcmp(aProviderName
, providerName
) == 0 )
253 int typeCount
= types
.size();
254 const char* typeNames
[typeCount
];
255 //fprintf(stderr, "types for %s:\n", providerName);
257 for(CStringSet::iterator it
= types
.begin(); it
!= types
.end(); ++it
) {
258 typeNames
[index
] = *it
;
259 //fprintf(stderr, "\t%s\n", *it);
263 // build list of probe/isenabled sites
264 const uint32_t probeCount
= probes
.size();
265 const char* probeNames
[probeCount
];
266 const char* funtionNames
[probeCount
];
267 uint64_t offsetsInDOF
[probeCount
];
269 for(std::vector
<DTraceProbeInfo
>::const_iterator it
= probes
.begin(); it
!= probes
.end(); ++it
) {
270 probeNames
[index
] = it
->probeName
;
271 funtionNames
[index
] = it
->atom
->name();
272 offsetsInDOF
[index
] = 0;
276 fprintf(stderr
, "calling libtrace to create DOF:\n");
277 fprintf(stderr
, " types::\n");
278 for(int i
=0; i
< typeCount
; ++i
)
279 fprintf(stderr
, " [%u]\t %s\n", i
, typeNames
[i
]);
280 fprintf(stderr
, " probes::\n");
281 for(uint32_t i
=0; i
< probeCount
; ++i
)
282 fprintf(stderr
, " [%u]\t %s in %s\n", i
, probeNames
[i
], funtionNames
[i
]);
285 // call dtrace library to create DOF section
286 size_t dofSectionSize
;
287 uint8_t* p
= (*pCreateDOF
)(opts
.architecture(), typeCount
, typeNames
, probeCount
, probeNames
, funtionNames
, offsetsInDOF
, &dofSectionSize
);
289 char* sectionName
= new char[18]; // alloc new string, pass ownership to File()
290 strcpy(sectionName
, "__dof_");
291 strlcpy(§ionName
[6], providerName
, 10);
292 // create unique section name so each DOF is in its own section
293 if ( sectionNamesUsed
.count(sectionName
) != 0 ) {
294 sectionName
[15] = '0';
295 sectionName
[16] = '\0';
296 while ( sectionNamesUsed
.count(sectionName
) != 0 ) {
300 sectionNamesUsed
.insert(sectionName
);
301 char symbolName
[strlen(providerName
)+64];
302 sprintf(symbolName
, "__dtrace_dof_for_provider_%s", providerName
);
303 File
* f
= new File("__TEXT", sectionName
, "dtrace", p
, dofSectionSize
, ld::File::Ordinal::NullOrdinal(), symbolName
);
305 fprintf(stderr
, "libdtrace created DOF of size %ld\n", dofSectionSize
);
308 f
->reserveFixups(3*probeCount
);
309 for (uint32_t i
=0; i
< probeCount
; ++i
) {
310 uint64_t offset
= offsetsInDOF
[i
];
311 //fprintf(stderr, "%s offset[%d]=0x%08llX\n", providerName, i, offset);
312 if ( offset
> dofSectionSize
)
313 throwf("offsetsInDOF[%d]=%0llX > dofSectionSize=%0lX\n", i
, offset
, dofSectionSize
);
314 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k1of4
, ld::Fixup::kindSetTargetAddress
, probes
[i
].atom
));
315 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k2of4
, ld::Fixup::kindAddAddend
, probes
[i
].offset
));
316 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k3of4
, ld::Fixup::kindSubtractTargetAddress
, &f
->atom()));
317 f
->addSectionFixup(ld::Fixup(offset
, ld::Fixup::k4of4
, storeKind
));
319 // insert new section
320 internal
.addAtom(f
->atom());
323 throw "error creating dtrace DOF section";
332 } // namespace dtrace
333 } // namespace passes