]>
git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/walkers.h
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 // walkers - facilities for traversing and manipulating recursive data structures
22 // Very briefly, this facility allows for deep traversals of (potentially) recursive
23 // data structures through templated structure "walkers." Standard operations include
24 // deep copying to a contiguous memory buffer, size calculation, and reconstitution
25 // after relocation (e.g. via IPC). You can add other operations (e.g. scattered deep
26 // copy, debug dumping, etc.) by defining operations classes and applying them to the
27 // existing walkers. You can also extend the reach of the facility to new data structures
28 // by writing appropriate walker functions for them.
30 // For more detailed rules and regulations, see the accompanying documentation.
35 #include <Security/utilities.h>
36 #include <Security/cssmalloc.h>
37 #include <Security/memstreams.h>
38 #include <Security/debugging.h>
43 namespace DataWalkers
{
48 #if defined(WALKERDEBUG)
49 # define DEBUGWALK(who) secdebug("walkers", "walk " who " %s@%p (%ld)", \
50 Debug::typeName(addr).c_str(), addr, size)
52 # define DEBUGWALK(who) /* nothing */
57 // Standard operators for sizing, copying, and reinflating
59 class SizeWalker
: public LowLevelMemoryUtilities::Writer::Counter
{
62 void operator () (T
&obj
, size_t size
= sizeof(T
)) { }
65 void operator () (T
*addr
, size_t size
= sizeof(T
))
66 { DEBUGWALK("size"); LowLevelMemoryUtilities::Writer::Counter::insert(size
); }
68 void blob(void *addr
, size_t size
)
69 { (*this)(addr
, size
); }
71 void reserve(size_t space
)
72 { LowLevelMemoryUtilities::Writer::Counter::insert(space
); }
74 static const bool needsRelinking
= false;
75 static const bool needsSize
= true;
78 class CopyWalker
: public LowLevelMemoryUtilities::Writer
{
81 CopyWalker(void *base
) : LowLevelMemoryUtilities::Writer(base
) { }
85 void operator () (T
&obj
, size_t size
= sizeof(T
))
89 void operator () (T
* &addr
, size_t size
= sizeof(T
))
93 addr
= reinterpret_cast<T
*>(LowLevelMemoryUtilities::Writer::operator () (addr
, size
));
97 void blob(T
* &addr
, size_t size
)
98 { (*this)(addr
, size
); }
100 static const bool needsRelinking
= true;
101 static const bool needsSize
= true;
104 class ReconstituteWalker
{
106 ReconstituteWalker(off_t offset
) : mOffset(offset
) { }
107 ReconstituteWalker(void *ptr
, void *base
)
108 : mOffset(LowLevelMemoryUtilities::difference(ptr
, base
)) { }
111 void operator () (T
&obj
, size_t size
= sizeof(T
))
115 void operator () (T
* &addr
, size_t size
= 0)
117 DEBUGWALK("reconstitute");
119 addr
= LowLevelMemoryUtilities::increment
<T
>(addr
, mOffset
);
123 void blob(T
* &addr
, size_t size
)
124 { (*this)(addr
, size
); }
126 static const bool needsRelinking
= true;
127 static const bool needsSize
= false;
133 class ChunkCopyWalker
{
135 ChunkCopyWalker(CssmAllocator
&alloc
= CssmAllocator::standard()) : allocator(alloc
) { }
137 CssmAllocator
&allocator
;
140 void operator () (T
&obj
, size_t size
= sizeof(T
))
144 void operator () (T
* &addr
, size_t size
= sizeof(T
))
146 DEBUGWALK("chunkcopy");
148 T
*copy
= reinterpret_cast<T
*>(allocator
.malloc(size
));
150 T
*copy
= allocator
.malloc
<T
>(size
);
152 memcpy(copy
, addr
, size
);
157 void blob(T
* &addr
, size_t size
)
158 { (*this)(addr
, size
); }
160 static const bool needsRelinking
= true;
161 static const bool needsSize
= true;
164 class ChunkFreeWalker
{
166 ChunkFreeWalker(CssmAllocator
&alloc
= CssmAllocator::standard()) : allocator(alloc
) { }
168 CssmAllocator
&allocator
;
171 void operator () (T
&obj
, size_t size
= 0)
175 void operator () (T
*addr
, size_t size
= 0)
177 DEBUGWALK("chunkfree");
178 freeSet
.insert(addr
);
181 void blob(void *addr
, size_t size
)
182 { (*this)(addr
, 0); }
185 ~ChunkFreeWalker() { free(); }
187 static const bool needsRelinking
= false;
188 static const bool needsSize
= false;
191 std::set
<void *> freeSet
;
196 // Stand-alone operations for a single structure web
208 T
*copy(const T
*obj
, void *addr
)
214 return reinterpret_cast<T
*>(addr
);
218 T
*copy(const T
*obj
, CssmAllocator
&alloc
= CssmAllocator::standard())
220 return obj
? copy(obj
, alloc
, size(obj
)) : NULL
;
224 T
*copy(const T
*obj
, CssmAllocator
&alloc
, size_t size
)
228 return copy(obj
, alloc
.malloc(size
));
232 void copy(const T
*obj
, CssmAllocator
&alloc
, CssmData
&data
)
238 if (data
.data() == NULL
) {
239 size_t length
= size(obj
);
240 data
= CssmData(alloc
.malloc(length
), length
);
242 assert(size(obj
) <= data
.length());
243 copy(obj
, data
.data());
248 void relocate(T
*obj
, T
*base
)
251 ReconstituteWalker
w(LowLevelMemoryUtilities::difference(obj
, base
));
258 T
*chunkCopy(const T
*obj
, CssmAllocator
&alloc
= CssmAllocator::standard())
261 ChunkCopyWalker
w(alloc
);
268 void chunkFree(const T
*obj
, CssmAllocator
&alloc
= CssmAllocator::standard())
271 ChunkFreeWalker
w(alloc
);
279 Copier(const T
*obj
, CssmAllocator
&alloc
= CssmAllocator::standard()) : allocator(alloc
)
287 mValue
= reinterpret_cast<T
*>(alloc
.malloc(mLength
));
289 mValue
= alloc
.malloc
<T
>(mLength
);
291 mValue
= copy(obj
, mValue
);
295 Copier(const T
*obj
, uint32 count
, CssmAllocator
&alloc
= CssmAllocator::standard())
303 sizer
.reserve(sizeof(T
) * count
); // initial vector size
304 for (uint32 n
= 0; n
< count
; n
++)
305 walk(sizer
, obj
[n
]); // dependent data sizes
308 mValue
= reinterpret_cast<T
*>(alloc
.malloc(mLength
));
310 mValue
= alloc
.malloc
<T
>(mLength
);
312 CopyWalker
copier(LowLevelMemoryUtilities::increment(mValue
, sizeof(T
) * count
));
313 for (uint32 n
= 0; n
< count
; n
++) {
315 walk(copier
, mValue
[n
]);
320 CssmAllocator
&allocator
;
322 ~Copier() { allocator
.free(mValue
); }
324 T
*value() const { return mValue
; }
325 operator T
*() const { return value(); }
326 size_t length() const { return mLength
; }
328 T
*keep() { T
*result
= mValue
; mValue
= NULL
; return result
; }
337 // Allow const pointer input but cast the const-ness away.
338 // This is valid because the walkers never directly *write* into *obj;
339 // they just pass their parts along to operate(). If we are in a writing
340 // pass, operate() must ensure it copies (and replaces) its argument to
342 // (The alternative design calls for three walk() functions for each type,
343 // which is ugly and error prone.)
345 template <class Action
, class T
>
346 T
*walk(Action
&operate
, const T
* &obj
)
347 { return walk(operate
, const_cast<T
* &>(obj
)); }
351 // The generic default walkers assume no structure, i.e. no recursive walks
353 template <class Action
, class Type
>
354 void walk(Action
&operate
, Type
&obj
)
359 template <class Action
, class Type
>
360 Type
*walk(Action
&operate
, Type
* &obj
)
367 } // end namespace DataWalkers
368 } // end namespace Security