Update copyright to LGPL on all files
[dyninst.git] / dynutil / h / Serialization.h
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #if !defined (SERIALIZATION_PUBLIC_H)
33 #define SERIALIZATION_PUBLIC_H
34 //  Hopefully just a few definitions allowing for a public interface to 
35 //  serializing user-providede annotations
36
37 #include <stdio.h>
38 #include <assert.h>
39 #include <string.h>
40 #include <stdexcept>
41 #include <typeinfo>
42 #include <vector>
43 #include <map>
44 #include <assert.h>
45 #include "dyntypes.h"
46 #include "util.h"
47 #include "Annotatable.h"
48 #include "dyn_detail/boost/type_traits/is_fundamental.hpp"
49 #include "dyn_detail/boost/type_traits/is_const.hpp"
50 #include "dyn_detail/boost/type_traits/remove_cv.hpp"
51 #include "dyn_detail/boost/type_traits/is_pointer.hpp"
52 #include "dyn_detail/boost/type_traits/is_enum.hpp"
53 #include "dyn_detail/boost/type_traits/alignment_of.hpp"
54 #include "dyn_detail/boost/type_traits/type_with_alignment.hpp"
55 #include "dyn_detail/boost/type_traits/remove_pointer.hpp"
56
57 #define SERIALIZE_CONTROL_ENV_VAR "DYNINST_SERIALIZE_ENABLE"
58 #define SERIALIZE_DISABLE "disable"
59 #define SERIALIZE_ONLY "serialize_but_dont_deserialize"
60 #define SERIALIZE_DESERIALIZE "deserialize"
61 #define SERIALIZE_DESERIALIZE_OR_DIE "deser_or_die"
62 #define DESERIALIZE_FORCE_ENV_VAR "DYNINST_DESERIALIZE_FORCE"
63
64 namespace Dyninst 
65 {
66 #if 0
67 //  throw_ser_err(FILE__, __LINE__,"msg") -- an attempt at "graceful" failure.  If debug flag is set
68 //  it will assert, otherwise it throws...  leaving the "graceful" aspect
69 //  to the next (hopefully top-level) exception handler.
70 //  UPDATE -- due to vtable recognition probs between modules (dyninst libs and
71 //  testsuite executables) no longer asserts.
72         
73
74
75 #define throw_ser_err(FILE__, __LINE__,cmsg) \
76    do { \
77       if (serializer_debug_flag()) { \
78          serialize_printf("SER_ERR: %s", cmsg); \
79          throw SerializerError(__FILE__, __LINE__, std::string(cmsg)); \
80       } else { \
81          throw SerializerError(__FILE__, __LINE__, std::string(cmsg)); \
82       } \
83    } while (0)
84 #endif
85
86 COMMON_EXPORT bool &serializer_debug_flag();
87
88 class SerializerBase;
89
90 typedef enum {sd_serialize, sd_deserialize} iomode_t;
91
92 class SerializerError {
93    //  SerializerError:  a small class that is thrown by serialization/deserialization
94    //  routines.  This exists as an attempt to standardize and simplify error handling
95    //  for ser-des routines that are possibly deeply nested.
96    //  Here's the rub:  we don't want stray, unhandled exceptions finding their way into
97    //  the larger system...  thus all entry points to serialization/deserialization need
98    //  to catch this exception to render it transparent to the rest of the system.
99
100    public:
101
102    typedef enum {
103       ser_err_unspecified,
104       ser_err_no_err,
105       ser_err_disabled
106    } SerializerErrorType;
107
108    private:
109
110    std::string msg__;
111    std::string file__;
112    int line__;
113    SerializerErrorType err__;
114
115    public:
116
117    COMMON_EXPORT SerializerError(const std::string &__file__, 
118          const int &__line__, 
119          const std::string &msg, 
120          SerializerErrorType __err__ = ser_err_unspecified) :
121       msg__(msg),
122       file__(__file__),
123       line__(__line__),
124       err__(__err__)
125    {}
126
127    COMMON_EXPORT virtual ~SerializerError() THROW {}
128
129    COMMON_EXPORT std::string file() const {return file__;}
130    COMMON_EXPORT std::string msg() const {return msg__;}
131    COMMON_EXPORT const char* what() const {return msg__.c_str();}
132    COMMON_EXPORT int line() const {return line__;}
133    COMMON_EXPORT SerializerErrorType code() const {return err__;}
134 };
135
136 COMMON_EXPORT void printSerErr(const SerializerError &err);
137
138 typedef enum {
139         ser_bin,
140         ser_xml,
141 } ser_type_t;
142
143 class SerContextBase 
144 {
145         friend class Serializable;
146         friend class SerializerBase;
147         COMMON_EXPORT static std::vector<std::pair<std::string, dyn_hash_map<std::string, short>*> > ser_control_map;
148         std::string fname;
149         std::string serfilename;
150         static dyn_hash_map<std::string, short> *getMapForType(std::string);
151         public:
152
153         COMMON_EXPORT SerContextBase(std::string, std::string); 
154         COMMON_EXPORT virtual ~SerContextBase() {}
155         COMMON_EXPORT virtual void *getVoidContext() = 0;
156         COMMON_EXPORT virtual const char *getRootTypename() = 0;
157         COMMON_EXPORT static void enableSerialize(std::string, std::string, bool);
158         COMMON_EXPORT static void enableDeserialize(std::string, std::string, bool);
159         COMMON_EXPORT static void enforceDeserialize(std::string, std::string, bool);
160         COMMON_EXPORT static void enableSerDes(std::string, std::string, bool);
161         COMMON_EXPORT void enableSerialize(bool);
162         COMMON_EXPORT void enableDeserialize(bool);
163         COMMON_EXPORT void enforceDeserialize(bool);
164         COMMON_EXPORT void enableSerDes(bool);
165
166         COMMON_EXPORT bool serializeEnabled();
167         COMMON_EXPORT bool deserializeEnabled();
168         COMMON_EXPORT static bool deserializeEnforced(std::string, std::string);
169         COMMON_EXPORT bool deserializeEnforced();
170
171         COMMON_EXPORT std::string getSerFileName();
172         COMMON_EXPORT virtual bool isContextType(Serializable *) = 0;
173 };
174
175 template <class T>
176 class SerContext : public SerContextBase
177 {
178         T *scope;
179
180         public:
181
182         SerContext(T *scope_, std::string fname) : SerContextBase(std::string(typeid(T).name()), fname), scope(scope_) {}
183         ~SerContext() {}
184         void *getVoidContext() {return (void *) scope;}
185         const char *getRootTypename() {return typeid(T).name();}
186         T *getScope() {return scope;}
187         bool isContextType(Serializable *s) { return (NULL != dynamic_cast<T *>(s));}
188 };
189
190 class SerFile;
191 class SerDes;
192
193 class SerializerBase {
194         friend class Serializable;
195
196         public:
197         COMMON_EXPORT static std::vector<SerializerBase *> active_serializers;
198         //  TODO:  make these private or protected
199         static bool global_disable;
200         private:
201
202         SerFile *sf;
203         SerDes *sd;
204         SerContextBase *scon;
205         unsigned short ser_index;
206
207         std::string serializer_name;
208
209         typedef dyn_hash_map<std::string, SerializerBase *> subsystem_serializers_t;
210         COMMON_EXPORT static dyn_hash_map<std::string, subsystem_serializers_t> all_serializers;
211
212         dyn_hash_map<void *, AnnotatableSparse *> *sparse_annotatable_map;
213         dyn_hash_map<void *, AnnotatableDense *> *dense_annotatable_map;
214         void clearAnnotationMaps();
215         public:
216         COMMON_EXPORT void set_annotatable_sparse_map(AnnotatableSparse *, void *);
217         COMMON_EXPORT void set_annotatable_dense_map(AnnotatableDense *, void *);
218         COMMON_EXPORT unsigned short getIndex();
219         COMMON_EXPORT static void globalDisable();
220         COMMON_EXPORT static bool serializationDisabled();
221         COMMON_EXPORT static void globalEnable();
222
223         COMMON_EXPORT virtual bool isXML() = 0;
224         COMMON_EXPORT virtual bool isBin ()= 0;
225         COMMON_EXPORT bool isEOF();
226
227         COMMON_EXPORT SerContextBase *getContext();
228         COMMON_EXPORT bool isInput ();
229         COMMON_EXPORT bool isOutput ();
230         COMMON_EXPORT AnnotatableSparse *findSparseAnnotatable(void *id);
231         COMMON_EXPORT AnnotatableDense *findDenseAnnotatable(void *id);
232
233         COMMON_EXPORT static void dumpActiveBinSerializers();
234
235         COMMON_EXPORT SerializerBase(SerContextBase *scb, std::string name_, std::string filename,                 iomode_t dir, bool verbose);
236         COMMON_EXPORT SerializerBase();
237
238         COMMON_EXPORT virtual ~SerializerBase();
239
240         COMMON_EXPORT virtual SerDes &getSD();
241         COMMON_EXPORT SerFile &getSF(); 
242         COMMON_EXPORT std::string &name() {return serializer_name;}
243         COMMON_EXPORT static SerializerBase *getSerializer(std::string subsystem, std::string fname);
244         COMMON_EXPORT static bool addSerializer(std::string subsystem, std::string fname, SerializerBase *sb);
245         COMMON_EXPORT static bool removeSerializer(unsigned short);
246         COMMON_EXPORT virtual void vector_start(unsigned long &, const char * = NULL);
247         COMMON_EXPORT virtual void vector_end();
248         COMMON_EXPORT virtual void hash_map_start(unsigned long &size, const char *tag = NULL);
249         COMMON_EXPORT virtual void hash_map_end();
250         COMMON_EXPORT virtual void multimap_start(unsigned long &size, const char *tag = NULL);
251         COMMON_EXPORT virtual void multimap_end();
252         COMMON_EXPORT virtual void pair_start(const char *tag = NULL);
253         COMMON_EXPORT virtual void pair_end();
254         COMMON_EXPORT virtual void annotation_start(AnnotationClassID &a_id, void *&lparent_id, sparse_or_dense_anno_t &lsod, const char *);
255         COMMON_EXPORT virtual void annotation_end();
256         COMMON_EXPORT virtual void annotation_container_start(void *&id);
257         COMMON_EXPORT virtual void annotation_container_end();
258         COMMON_EXPORT virtual void annotation_container_item_start(void *&id);
259         COMMON_EXPORT virtual void annotation_container_item_end();
260         COMMON_EXPORT void translate_base(bool &v, const char *&t);
261         COMMON_EXPORT void translate_base(short &v, const char *&t);
262         COMMON_EXPORT void translate_base(unsigned short &v, const char *&t);
263         COMMON_EXPORT void translate_base(char &v, const char *&t);
264         COMMON_EXPORT void translate_base(int &v, const char *&t);
265         COMMON_EXPORT void translate_base(unsigned int &v, const char *&t);
266         COMMON_EXPORT void translate_base(unsigned long &v, const char *&t);
267         COMMON_EXPORT void translate_base(long &v, const char *&t);
268         COMMON_EXPORT void translate_base(float &v, const char *&t);
269         COMMON_EXPORT void translate_base(double &v, const char *&t);
270         COMMON_EXPORT void translate_base(const char * &v, int bufsize, const char *&t);
271         COMMON_EXPORT void translate_base(char * &v, int bufsize, const char *&t);
272         COMMON_EXPORT void translate_base(void * &v, const char *&t);
273         COMMON_EXPORT void translate_base(std::string &v, const char *t);
274         COMMON_EXPORT virtual void magic_check(const char *file__, unsigned int line__);
275
276         COMMON_EXPORT virtual iomode_t iomode();
277
278         COMMON_EXPORT void serialize_annotations(void *, std::vector<ser_rec_t> &sers, const char * = NULL);
279         COMMON_EXPORT bool serialize_post_annotation(void *parent_id, void *anno, AnnotationClassBase *acb, sparse_or_dense_anno_t , const char * = NULL);
280 };
281
282 SerializerBase *createSerializer(SerContextBase *, std::string, std::string, ser_type_t, iomode_t, bool = false);
283
284 class AnnotatableSparse;
285 class AnnotatableDense;
286 class AnnotationContainerBase;
287
288 COMMON_EXPORT void serialize_annotatable_id(SerializerBase *sb, void *&id, const char *tag);
289 COMMON_EXPORT bool set_sb_annotatable_sparse_map(SerializerBase *, AnnotatableSparse *, void *);
290 COMMON_EXPORT bool set_sb_annotatable_dense_map(SerializerBase *, AnnotatableDense *, void *);
291 COMMON_EXPORT unsigned short get_serializer_index(SerializerBase *sb);
292 COMMON_EXPORT void annotation_start(SerializerBase *, AnnotationClassID &, void *&, sparse_or_dense_anno_t &, const char *);
293 COMMON_EXPORT void annotation_end(SerializerBase *);
294 COMMON_EXPORT AnnotatableSparse *find_sparse_annotatable(SerializerBase *, void *);
295 COMMON_EXPORT AnnotatableDense *find_dense_annotatable(SerializerBase *, void *);
296 COMMON_EXPORT bool isEOF(SerializerBase *);
297 COMMON_EXPORT void throw_ser_err(const char *file__, unsigned int line, const char *msg);
298
299
300 COMMON_EXPORT void annotation_container_start(SerializerBase *sb, void *&id);
301 COMMON_EXPORT void annotation_container_end(SerializerBase *sb);
302 COMMON_EXPORT void annotation_container_item_start(SerializerBase *, void *&);
303 COMMON_EXPORT void annotation_container_item_end(SerializerBase *);
304 COMMON_EXPORT bool deserialize_container_item(SerializerBase *, void *);
305 COMMON_EXPORT AnnotationContainerBase *get_container(void *);
306 COMMON_EXPORT bool deserialize_container_item(AnnotationContainerBase *acb, SerializerBase *sb);
307
308 template <class T>
309 void enableSerialize(std::string fname, bool val)
310 {
311         serialize_printf("%s[%d]:  %s serialize for type %s\n", 
312                         FILE__, __LINE__, val ? "enabling" : "disabling", typeid(T).name());
313         SerContextBase::enableSerialize(std::string(typeid(T).name()), fname, val);
314 }
315
316 template <class T>
317 void enableDeserialize(std::string fname, bool val)
318 {
319         serialize_printf("%s[%d]:  %s deserialize for type %s\n", 
320                         FILE__, __LINE__, val ? "enabling" : "disabling", typeid(T).name());
321         SerContextBase::enableDeserialize(std::string(typeid(T).name()), fname, val);
322 }
323
324 template <class T>
325 void enforceDeserialize(std::string fname, bool val)
326 {
327         serialize_printf("%s[%d]:  %s enforced deserialize for type %s\n", 
328                         FILE__, __LINE__, val ? "enabling" : "disabling", typeid(T).name());
329         SerContextBase::enforceDeserialize(std::string(typeid(T).name()), fname, val);
330 }
331
332 template <class T>
333 bool deserializeEnforced(std::string fname)
334 {
335         return SerContextBase::deserializeEnforced(std::string(typeid(T).name()), fname);
336 }
337
338 template <class T>
339 void enableSerDes(std::string fname, bool val)
340 {
341         serialize_printf("%s[%d]:  %s serialize/deserialize for type %s\n", 
342                         FILE__, __LINE__, val ? "enabling" : "disabling", typeid(T).name());
343         SerContextBase::enableSerDes(std::string(typeid(T).name()), fname, val);
344 }
345
346 class Serializable {
347         bool was_deserialized;
348         static void clearContainersByID();
349
350         protected:
351         unsigned short active_serializer_index;
352
353         COMMON_EXPORT Serializable() : 
354                 was_deserialized(false), 
355                 active_serializer_index((unsigned short) (-1)) {}
356
357         COMMON_EXPORT virtual ~Serializable() 
358         {
359                 if (active_serializer_index != (unsigned short) -1)
360                 {
361                         SerializerBase *sb = getExistingOutputSB(active_serializer_index);
362                         if (sb)
363                         {
364                                 SerContextBase *scb = sb->getContext();
365                                 if (scb->isContextType(this))
366                                 {
367                                         //  hrm...  not sure this works as intended.
368                                         fprintf(stderr, "%s[%d]:  TOP LEVEL SERIALIZE DONE:  removing serializer\n", FILE__, __LINE__);
369                                         sb->removeSerializer(active_serializer_index);
370                                 }
371                         }
372                 }
373         }
374
375         COMMON_EXPORT virtual Serializable *serialize_impl(SerializerBase *,  const char * = NULL) THROW_SPEC(SerializerError) = 0;
376
377         public:
378
379         COMMON_EXPORT unsigned short getID() {return active_serializer_index;}
380
381         COMMON_EXPORT bool serialize(std::string filename, SerContextBase *scb, ser_type_t);
382
383         COMMON_EXPORT bool deserialize(std::string filename, SerContextBase *scb) 
384         {
385                 std::string sername = std::string("Deserializer");
386
387                 SerializerBase *serializer = createSerializer(scb, sername, filename, 
388                                 ser_bin, sd_deserialize, /*verbose*/ false);
389
390                 if (!serializer) 
391                 {
392                         serialize_printf("%s[%d]:  ERROR:  failed to create deserializer for %s\n", 
393                                         FILE__, __LINE__, filename.c_str());
394                         clearContainersByID();
395                         return false;
396                 }
397
398                 try
399                 {
400                         //  Do the serialization
401                         serialize(serializer, NULL);
402                 }
403                 catch (const SerializerError &err_)
404                 {
405                         serialize_printf("%s[%d]:  deserialize failed\n", FILE__, __LINE__);
406                         printSerErr(err_);
407                         serializer->clearAnnotationMaps();
408                         clearContainersByID();
409                         return false;
410                 }
411                 catch (...)
412                 {
413                         serialize_printf("%s[%d]:  caught unexpected exception\n", FILE__, __LINE__);
414                         serializer->clearAnnotationMaps();
415                         clearContainersByID();
416                         return false;
417                 }
418
419                 void *barrier_magic = (void *) 0xdeadbeef;
420                 serialize_annotatable_id(serializer, barrier_magic, NULL);
421
422                 if (barrier_magic != (void *)0xdeadbeef)
423                 {
424                         fprintf(stderr, "%s[%d]:  FIXME:  failed to read magic barrier\n", FILE__, __LINE__);
425                 }
426
427                 unsigned op_count = 0;
428                 while (1)
429                 {
430                         try
431                         {
432                                 void *my_anno = NULL;
433                                 void *parent_id = NULL;
434                                 ser_post_op_t op = sp_add_anno;
435                                 AnnotationClassBase *acb = NULL;
436                                 sparse_or_dense_anno_t sod = sparse;
437                                 AnnotationClassID a_id = 0;
438
439                                 serializer_printf("%s[%d]:  reading post-serialize item %d\n", 
440                                                 FILE__, __LINE__, op_count);
441
442                                 if (!ser_operation(serializer, op, NULL))
443                                 {
444                                         if (isEOF(serializer))
445                                         {
446                                                 serialize_printf("%s[%d]:  got EOF\n", FILE__, __LINE__);
447                                                 serializer->clearAnnotationMaps();
448                                                 clearContainersByID();
449                                                 return true;
450                                         }
451                                 }
452                                 switch (op) {
453                                         case sp_add_anno:
454                                                 {
455                                                 annotation_start(serializer, a_id, parent_id, sod, NULL);
456                                                 acb = AnnotationClassBase::findAnnotationClass(a_id);
457                                                 if (!acb)
458                                                 {
459                                                         fprintf(stderr, "%s[%d]:  failed to find annotation type %d\n", 
460                                                                         FILE__, __LINE__, a_id);
461                                                         serializer->clearAnnotationMaps();
462                                                         clearContainersByID();
463                                                         return false;
464                                                 }
465                                                 else
466                                                 {
467                                                         serializer_printf("%s[%d]:  found annotation id %d/%d\n", 
468                                                                         FILE__, __LINE__, acb->getID(), a_id);
469                                                 }
470
471                                                 my_anno = acb->allocate();
472                                                 assert(my_anno);
473
474                                                 ser_func_t sf = acb->getSerializeFunc();
475                                                 if (!sf)
476                                                 {
477                                                         fprintf(stderr, "%s[%d]:  failed to find serialization function\n", 
478                                                                         FILE__, __LINE__);
479                                                         serializer->clearAnnotationMaps();
480                                                         clearContainersByID();
481                                                         return false;
482                                                 }
483
484                                                 //  execute the serialization function for this annotation
485                                                 serializer_printf("%s[%d]:  calling serialize func for type %s\n",
486                                                                 FILE__, __LINE__, acb->getTypeName());
487
488                                                 (*sf)(my_anno, serializer, NULL);
489
490                                                 serializer_printf("%s[%d]:  called serialize func for type %s\n",
491                                                                 FILE__, __LINE__, acb->getTypeName());
492
493                                                 annotation_end(serializer);
494
495                                                 //  we have the (void *) annotation and the annotation type
496                                                 //  now lookup the object to which it belonged in the map of 
497                                                 //  annotatable objects
498                                                 //  and add it as an annotation.
499
500                                                 if (sparse == sod)
501                                                 {
502                                                         AnnotatableSparse *as = find_sparse_annotatable(serializer, parent_id);
503                                                         if (NULL == as)
504                                                         {
505                                                                 fprintf(stderr, "%s[%d]:  ERROR:  cannot find anno parent id %p for anno of type %s\n",
506                                                                                 FILE__, __LINE__, parent_id, acb->getTypeName());
507                                                         }
508                                                         else
509                                                         {
510                                                                 assert(acb);
511
512                                                                 if (!as->addAnnotation(my_anno, acb->getID()))
513                                                                 {
514                                                                         fprintf(stderr, "%s[%d]:  ERROR:  failed to add annotation here\n",
515                                                                                         FILE__, __LINE__);
516                                                                 }
517
518                                                                 //  Need to consider case if annotatee is itself annotatable
519                                                                 //  this should be tested  (should transparently end up in
520                                                                 //  the annotatable-object mapping, but not sure if it does 
521                                                                 //  right now)
522                                                         }
523                                                 }
524                                                 else if (dense == sod)
525                                                 {
526                                                         AnnotatableDense *ad = find_dense_annotatable(serializer, parent_id);
527                                                         if (NULL == ad)
528                                                         {
529                                                                 fprintf(stderr, "%s[%d]:  ERROR:  cannot find anno parent id = %p\n",
530                                                                                 FILE__, __LINE__, (void *) parent_id);
531                                                         }
532                                                         else
533                                                         {
534                                                                 assert(acb);
535                                                                 serializer_printf("%s[%d]:  reading post annotation\n", 
536                                                                                 FILE__, __LINE__);
537                                                                 if (!ad->addAnnotation(my_anno, acb->getID()))
538                                                                 {
539                                                                         fprintf(stderr, "%s[%d]:  ERROR:  failed to add annotation here\n",
540                                                                                         FILE__, __LINE__);
541                                                                 }
542                                                         }
543                                                 }
544                                                 else
545                                                 {
546                                                         fprintf(stderr, "%s[%d]:  ERROR:  sparse/dense not set properly\n", 
547                                                                         FILE__, __LINE__);
548                                                         serializer->clearAnnotationMaps();
549                                                         clearContainersByID();
550                                                         return false;
551                                                 }
552                                                 break;
553                                                 }
554                                         case sp_rem_anno:
555                                                 {
556                                                         fprintf(stderr, "%s[%d]:  FIXME:  not implemented\n", FILE__, __LINE__);
557                                                 break;
558                                                 }
559                                         case sp_add_cont_item:
560                                                 {
561                                                         void *parent_id = NULL;
562                                                         annotation_container_item_start(serializer, parent_id);
563                                                         if (!parent_id)
564                                                         {
565                                                                 fprintf(stderr, "%s[%d]:  NULL container with id\n", 
566                                                                                 FILE__, __LINE__);
567                                                                 serializer->clearAnnotationMaps();
568                                                                 clearContainersByID();
569                                                                 return false;
570                                                         }
571
572                                                         if (!deserialize_container_item(serializer, parent_id))
573                                                         {
574                                                                 fprintf(stderr, "%s[%d]:  failed deser contitem w/parent %p\n", 
575                                                                                 FILE__, __LINE__, parent_id);
576                                                                 serializer->clearAnnotationMaps();
577                                                                 clearContainersByID();
578                                                                 return false;
579                                                         }
580
581                                                         annotation_container_item_end(serializer);
582                                                         break;
583                                                 }
584                                         case sp_rem_cont_item:
585                                                 {
586                                                         fprintf(stderr, "%s[%d]:  FIXME:  not implemented\n", 
587                                                                         FILE__, __LINE__);
588                                                 break;
589                                                 }
590                                         default:
591                                                 fprintf(stderr, "%s[%d]:  ERROR:  bad ser operation %d\n", 
592                                                                 FILE__, __LINE__, op);
593                                                 serializer->clearAnnotationMaps();
594                                                 clearContainersByID();
595                                                 return false;
596                                 };
597
598                                 if (isEOF(serializer))
599                                 {
600                                         fprintf(stderr, "%s[%d]:  got EOF\n", FILE__, __LINE__);
601                                         serializer->clearAnnotationMaps();
602                                         clearContainersByID();
603                                         return true;
604                                 }
605
606                         }
607                         catch (const Dyninst::SerializerError &err_)
608                         {
609                                 if (isEOF(serializer))
610                                 {
611                                         serialize_printf("%s[%d]:  got EOF\n", FILE__, __LINE__);
612                                         serializer->clearAnnotationMaps();
613                                         clearContainersByID();
614                                         return true;
615                                 }
616                                 if (serializer_debug_flag()) 
617                                 {
618                                         fprintf(stderr, "%s[%d]:  deserialize caught exception\n", FILE__, __LINE__);
619                                         printSerErr(err_);
620                                 }
621                                 serializer->clearAnnotationMaps();
622                                 clearContainersByID();
623                                 return false;
624                         }
625                         catch (...)
626                         {
627                                 serialize_printf("%s[%d]:  caught unknown exception\n", FILE__, __LINE__);
628                                 if (isEOF(serializer))
629                                 {
630                                         serialize_printf("%s[%d]:  got EOF\n", FILE__, __LINE__);
631                                         serializer->clearAnnotationMaps();
632                                         clearContainersByID();
633                                         return true;
634                                 }
635                                 serializer->clearAnnotationMaps();
636                                 clearContainersByID();
637                                 return false;
638                         }
639                         op_count++;
640                 }
641
642                 serializer->clearAnnotationMaps();
643                 clearContainersByID();
644                 return true;
645         }
646
647         COMMON_EXPORT SerializerBase *lookupExistingSerializer();
648         COMMON_EXPORT bool from_cache() {return was_deserialized;}
649
650         COMMON_EXPORT virtual Serializable *serialize(SerializerBase *sb,  
651                         const char *tag = NULL) THROW_SPEC(SerializerError)
652         {
653                 //  This function must be implemented in the header file so that
654                 //  the vtables of AnnotatableSparse and AnnotatableDense resolve properly
655                 //  (only matters in case of testsuite, but it's nice to have finer grain 
656                 //  tests that this allows)
657
658                 //  do base serialization for this class
659
660                 sb->magic_check(FILE__, __LINE__);
661                 Serializable *res = serialize_impl(sb, tag);
662                 sb->magic_check(FILE__, __LINE__);
663
664                 //  then serialize all Annotations for which a serialization function has been provided
665                 void *id = this;
666
667                 AnnotatableSparse *as = dynamic_cast<AnnotatableSparse *> (this);
668                 if (as)
669                 {
670                         id = as;
671                         //  since this class is annotatable, serialize its id (address)
672                         //  so that we can later build a map of all annotatable objects
673                         //  by id, and apply post-annotations to them 
674
675                         sb->magic_check(FILE__, __LINE__);
676                         serialize_annotatable_id(sb, id, "SparseAnnotatableObjectID");
677                         sb->magic_check(FILE__, __LINE__);
678
679                         if (is_input(sb))  
680                         {
681                                 if (NULL != id)
682                                 {
683                                         if (!set_sb_annotatable_sparse_map(sb, as, id))
684                                         {
685                                                 fprintf(stderr, "%s[%d]:  failed to set annotatable-anno mapping here\n", 
686                                                                 FILE__, __LINE__);
687                                         }
688                                 }
689                                 else
690                                         fprintf(stderr, "%s[%d]:  ERROR:  id is NULL\n", FILE__, __LINE__);
691                         }
692
693                         if (is_output(sb))
694                                 serialize_printf("%s[%d]:  set anno mapping for %p\n", FILE__, __LINE__, id);
695
696                         sb->magic_check(FILE__, __LINE__);
697                         as->serializeAnnotations(sb, tag);
698                         sb->magic_check(FILE__, __LINE__);
699                 }
700                 else
701                 {
702                         AnnotatableDense *ad = dynamic_cast<AnnotatableDense *> (this);
703                         if (ad)
704                         {
705                                 //  since this class is annotatable, serialize its id (address)
706                                 //  so that we can later build a map of all annotatable objects
707                                 //  by id, and apply post-annotations to them 
708                                 id = ad;
709                                 sb->magic_check(FILE__, __LINE__);
710                                 serialize_annotatable_id(sb, id, "DenseAnnotatableObjectID");
711                                 sb->magic_check(FILE__, __LINE__);
712
713                                 serialize_printf("%s[%d]:  %sserializing annotatable id %p, this = %p\n", 
714                                                 FILE__, __LINE__, is_output(sb) ? "": "de", id, this);
715
716                                 if (is_input(sb))
717                                 {
718                                         if (NULL != id)
719                                         {
720                                                 //  add id to the map of annotatable objects, mapping to "this"
721
722                                                 if (!set_sb_annotatable_dense_map(sb, ad, id))
723                                                 {
724                                                         fprintf(stderr, "%s[%d]:  failed to set annotatable-annotation map\n",
725                                                                         FILE__, __LINE__);
726                                                 }
727
728                                                 serialize_printf("%s[%d]:  set dense annotatable mapping for id %p\n", 
729                                                                 FILE__, __LINE__, (void *)id);
730                                         }
731                                         else
732                                                 fprintf(stderr, "%s[%d]:  got NULL id in deserialize\n", FILE__, __LINE__);
733                                 }
734
735                                 sb->magic_check(FILE__, __LINE__);
736                                 ad->serializeAnnotations(sb, tag);
737                                 sb->magic_check(FILE__, __LINE__);
738                         }
739                         else
740                         {
741                                 serialize_printf("%s[%d]:  class %s is not annotatable\n", 
742                                                 FILE__, __LINE__, typeid(this).name());
743                         }
744                 }
745
746                 if (is_input(sb))
747                         was_deserialized = true;
748
749                 active_serializer_index = get_serializer_index(sb);
750
751                 return res;
752         }
753 };
754
755
756 class AnnotationContainerBase : public Serializable
757 {
758         friend class Serializable;
759         friend COMMON_EXPORT bool deserialize_container_item(SerializerBase *, void *);
760         friend COMMON_EXPORT bool deserialize_container_item(AnnotationContainerBase *, SerializerBase *);
761
762         protected:
763                 static dyn_hash_map<void *, AnnotationContainerBase *> containers_by_id;
764                 COMMON_EXPORT static void clearContainersByID();
765
766                 COMMON_EXPORT AnnotationContainerBase() {}
767                 COMMON_EXPORT virtual ~AnnotationContainerBase() {}
768                 COMMON_EXPORT virtual bool deserialize_item(SerializerBase *) = 0;
769
770         public:
771
772                 COMMON_EXPORT virtual Serializable *ac_serialize_impl(SerializerBase *,  
773                                 const char * = NULL) THROW_SPEC(SerializerError) = 0;
774
775                 COMMON_EXPORT virtual Serializable *serialize_impl(SerializerBase *sb,  
776                                 const char *tag = NULL) THROW_SPEC(SerializerError) 
777                 {
778                         void *id = this;
779                         annotation_container_start(sb, id);
780                         //  serialize the id of this container, then call the container serialize func
781                         //serialize_annotatable_id(sb, id, "ContainerID");
782                         Serializable *res = ac_serialize_impl(sb, tag);
783                         annotation_container_end(sb);
784
785                         if (is_input(sb))
786                         {
787                                 //  for deserialize build a hash of container ids
788                                 containers_by_id[id] = this;
789                         }
790                         annotatable_printf("%s[%d]: %s AnnotationContainer(%p) of type %s, id = %p\n",
791                                         FILE__, __LINE__, is_input(sb) ? "deserialized" : "serialized", this,
792                                         getElementTypename(), id);         
793                         return res;
794                 }       
795
796                 COMMON_EXPORT virtual const char *getElementTypename() = 0; 
797                 COMMON_EXPORT static AnnotationContainerBase *getContainer(void *id)
798                 {
799                         dyn_hash_map<void *, AnnotationContainerBase *>::iterator iter;
800
801                         iter = containers_by_id.find(id);
802                         if (iter == containers_by_id.end())
803                         {
804                                 fprintf(stderr, "%s[%d]:  ERROR:  cannot find id %p in container-id map\n", 
805                                                 FILE__, __LINE__, id);
806                                 return NULL;
807                         }
808
809                         return iter->second;
810                 }
811
812                 COMMON_EXPORT static void setContainerID(AnnotationContainerBase *acb, void *id)
813                 {
814                         //  Currently see no need to first check whether we have a duplicate here
815                         containers_by_id[id] = acb;
816                 }
817 };
818
819
820 template <class T>
821 Serializable *cont_ser_func_wrapper(void *it, SerializerBase *sb, const char *)
822 {
823         T *itt =  (T*) it;
824         gtranslate(sb, *itt);
825         return NULL;
826 }
827
828 #if 0
829 template <class T, typename IS_POINTER, typename IS_SERIALIZABLE>
830 class SerFuncExecutor 
831 {
832         AnnotationClass<T> *ac;
833
834         public:
835
836         SerFuncExecutor(AnnotationClass<T> *ac_) : ac(ac_) {}
837
838         Serializable *operator()(T &my_item, SerializerBase *sb, const char *tag = NULL) 
839         {
840                 ser_func_t sf = ac->getSerializeFunc();
841                 assert(sf);
842
843                 serialize_printf("%s[%d]:  calling serialize func for type %s\n",
844                                 FILE__, __LINE__, ac->getTypeName());
845
846                 Serializable *res = (*sf)(&my_item, sb, tag);
847                 return res;
848         }
849 };
850
851 template <class T>
852 class SerFuncExecutor<T, dyn_detail::boost::true_type, dyn_detail::boost::true_type>
853 {
854         AnnotationClass<T> *ac;
855
856         public:
857
858         SerFuncExecutor(AnnotationClass<T> *ac_) : ac(ac_) {}
859
860         void operator()(T &my_item, SerializerBase *sb, const char *tag = NULL) 
861         {
862                 ser_func_t sf = ac->getSerializeFunc();
863                 assert(sf);
864
865                 //  T is a pointer, and we need to alloc the object
866                 my_item = (T) ac->allocate();
867                 serialize_printf("%s[%d]:  calling serialize func for type %s\n",
868                                 FILE__, __LINE__, ac->getTypeName());
869
870                 Serializable *sable = (*sf)(my_item, sb, tag);
871
872                 T res = dynamic_cast<T>(sable);
873
874                 if (sable && !res)
875                 {
876                         fprintf(stderr, "%s[%d]:  ERROR:  %s not Serializable ??\n", 
877                                         FILE__, __LINE__, typeid(T).name());
878                 }
879
880                 if (res && (res != my_item))
881                 {
882                         fprintf(stderr, "%s[%d]:  serialize func for %s did a realloc\n", 
883                                         FILE__, __LINE__, typeid(T).name());
884                         fprintf(stderr, "%s[%d]:  REMOVED DELETE\n", FILE__, __LINE__);
885                         delete my_item;
886                         my_item = res;
887                 }
888                 serialize_printf("%s[%d]:  called serialize func for type %s\n",
889                                 FILE__, __LINE__, ac->getTypeName());
890         }
891 };
892 #endif
893
894 template <class T>
895 class AnnotationContainer : public AnnotationContainerBase
896 {
897 #if 0
898         //  We internally manage the annotation class (which includes serialize function)
899         //  for the elements of this container.  When the container is added as a annotation,
900         //  the element annotation class is thus not required in addition to the annotation
901         //  class that the user must supply for the container overall.
902
903         AnnotationClass<T> *ac;
904 #endif
905
906                 virtual bool deserialize_item(SerializerBase *sb)
907                 {
908                         T my_item;
909                         if (dyn_detail::boost::is_pointer<T>::value)
910                         {
911                                 //  if T is a class , memset would clobber the vptr
912                                 memset( &my_item, 0, sizeof(T));
913                         }
914
915                         if (!sb)
916                         {
917                                 fprintf(stderr, "%s[%d]:  FIXME:  bad param\n", FILE__, __LINE__);
918                                 return false;
919                         }
920 #if 0 
921                         ser_func_t sf = ac->getSerializeFunc();
922
923                         if (!sf)
924                         {
925                                 fprintf(stderr, "%s[%d]:  failed to find serialization function\n", 
926                                                 FILE__, __LINE__);
927                                 return false;
928                         }
929
930                         SerFuncExecutor<T, typename dyn_detail::boost::is_pointer<T>::type, 
931                                 typename dyn_detail::boost::is_base_of<Serializable, 
932                                 typename dyn_detail::boost::remove_pointer<T>::type>::type>  
933                                         sfe(ac);
934
935                         sfe(my_item, sb);
936 #else
937                         gtranslate(sb, my_item);
938 #endif
939
940                         if (!addItem_impl(my_item))
941                         {
942                                 fprintf(stderr, "%s[%d]:  failed to addItem after deserialize\n", FILE__, __LINE__);
943                                 return false;
944                         }
945
946                         return true;
947                 }
948
949         public:
950
951
952                 AnnotationContainer() 
953 #if 0
954                         : ac(NULL)
955 #endif
956                 {
957 #if 0
958                         ser_func_t sf = NULL;
959
960                         if (dyn_detail::boost::is_fundamental<T>::value)
961                         {
962                                 sf = (ser_func_t) cont_ser_func_wrapper<T>;
963                         }
964
965                         std::string aname = std::string(typeid(*this).name()) + std::string("_elem");
966                         ac = new AnnotationClass<T>(aname, NULL, sf);
967 #endif
968                 }
969
970                 ~AnnotationContainer()
971                 {/* if (ac) delete ac; */}
972
973                 //  The routine that actually adds the item and manages whatever data structure
974                 //  the container is using.  Must be provided by descendant class.
975
976                 virtual bool addItem_impl(T t) = 0;
977
978                 bool addItem(T t) 
979                 {
980                         if (!addItem_impl(t))
981                         {
982                                 fprintf(stderr, "%s[%d]:  failed to add item of type %s to container\n", 
983                                                 FILE__, __LINE__, typeid(T).name());
984                                 return false;
985                         }
986
987                         //  If a serialization has already occurred for the container, serialize this item too
988
989                         SerializerBase *sb = lookupExistingSerializer();
990                         if (sb)
991                         {
992                                 //  T must be either a basic type or a descendant of Serializable
993                                 ser_post_op_t op =  sp_add_cont_item;
994                                 void *id = this;
995                                 ser_operation(sb, op, NULL);
996                                 annotation_container_item_start(sb, id);
997                                 gtranslate(sb, t, NULL);
998                                 annotation_container_item_end(sb);
999                         }
1000                         return true;
1001                 }       
1002
1003                 virtual const char *getElementTypename() {return typeid(T).name();}
1004
1005                 virtual Serializable *ac_serialize_impl(SerializerBase *, 
1006                                 const char *tag) THROW_SPEC(SerializerError) = 0;
1007 };
1008
1009 template <typename T>
1010 void translate_vector(SerializerBase *ser, std::vector<T> &vec,
1011                 const char *tag = NULL, const char *elem_tag = NULL)
1012 {
1013         unsigned long nelem = 0UL;
1014
1015         if (ser->iomode() == sd_serialize)
1016                 nelem = (unsigned long) vec.size();
1017
1018         ser->vector_start(nelem, tag);
1019
1020         if (ser->iomode() == sd_deserialize) 
1021         {
1022                 if (vec.size())
1023                         throw_ser_err(FILE__, __LINE__,"nonempty vector used to create");
1024
1025                 //  zero size vectors are allowed
1026                 serialize_printf("%s[%d]:  about to resize vector to %lu\n", 
1027                                 FILE__, __LINE__, nelem);
1028
1029                 if (nelem)
1030                         vec.resize(nelem);
1031         }
1032
1033         for (unsigned long i = 0; i < nelem; ++i) 
1034         {
1035                 gtranslate(ser, vec[i], elem_tag);
1036 #if 0
1037                 if (ser->isOutput())
1038                         gtranslate(ser, vec[i], elem_tag);
1039                 else
1040                 {
1041                         T t;
1042                         gtranslate(ser, t, elem_tag);
1043                         vec.push_back(t);
1044                 }
1045 #endif
1046 #if 0
1047                 T t;
1048                 if (ser->isOutput())
1049                         t = vec[i];
1050                 //T &t = vec[i];
1051                 //memset(&(vec[i]), 0, sizeof(T));
1052                 gtranslate(ser, t, elem_tag);
1053                 if (ser->isInput())
1054                         vec[i] = t;
1055 #endif
1056         }
1057
1058         ser->vector_end();
1059 }
1060
1061 template <typename K, typename V>
1062 void translate_pair(SerializerBase *ser, std::pair<K, V> &p,
1063                 const char *tag = NULL, const char *tag2 = NULL)
1064 {
1065         ser->pair_start();
1066
1067         gtranslate(ser, p.first, tag);
1068         gtranslate(ser, p.second, tag2);
1069
1070         ser->pair_end();
1071 }
1072
1073 template <typename T, typename T2>
1074 struct pair_translator {
1075         void operator()(SerializerBase *ser, std::pair<T, T2> &p, 
1076                         const char *tag = NULL, const char *tag2 = NULL)
1077 {
1078         ser->pair_start();
1079
1080         gtranslate(ser,  p.first, tag);
1081         gtranslate(ser,  p.second, tag2);
1082
1083         ser->pair_end();
1084 }
1085 };
1086
1087 template <class S, class K, class V>
1088 void translate_dyn_hash_map(S *ser, dyn_hash_map<K, V> &map,
1089                 const char *tag = NULL, const char *elem_tag = NULL)
1090 {
1091         serialize_printf("%s[%d]:  welcome to translate_dyn_hash_map<%s, %s>, size = %ld\n", 
1092                         FILE__, __LINE__, typeid(K).name(), typeid(V).name(), map.size());
1093
1094         unsigned long nelem = 0UL;
1095         nelem = map.size();
1096         ser->hash_map_start(nelem, tag);
1097
1098         if (ser->iomode() == sd_deserialize)
1099         {
1100                 if (map.size())
1101                         throw_ser_err(FILE__, __LINE__,"nonempty vector used to create");
1102
1103                 for (unsigned long i = 0UL; i < nelem; ++i)
1104                 {
1105                         typename dyn_hash_map<K, V>::value_type mapentry;
1106                         gtranslate(ser, mapentry, elem_tag);
1107                         map.insert(mapentry);
1108                 }
1109         }
1110         else
1111         {
1112                 assert (ser->iomode() == sd_serialize);
1113                 typename dyn_hash_map<K, V>::iterator iter = map.begin();
1114                 while (iter != map.end())
1115                 {
1116                         gtranslate(ser, *iter, elem_tag);
1117                         iter++;
1118                 }
1119         }
1120
1121         ser->hash_map_end();
1122
1123         serialize_printf("%s[%d]:  leaving translate_dyn_hash_map<%s, %s>\n", 
1124                         FILE__, __LINE__, typeid(K).name(), typeid(V).name());
1125 }
1126
1127 template <class S, class K, class V>
1128 void translate_map(S *ser, std::map<K, V> &map,
1129                 const char *tag = NULL, const char *elem_tag = NULL)
1130 {
1131         unsigned long nelem = 0UL;
1132         nelem = map.size();
1133         ser->map_start(nelem, tag);
1134
1135         if (ser->iomode() == sd_deserialize)
1136         {
1137                 if (map.size())
1138                         throw_ser_err(FILE__, __LINE__,"nonempty vector used to create");
1139
1140                 typename std::map<K, V>::iterator lastentry = map.begin();
1141                 //  cannot do any kind of bulk allocation with maps
1142                 for (unsigned int i = 0; i < nelem; ++i)
1143                 {
1144                         K a_k;
1145                         V a_v;
1146                         gtranslate(ser, a_k, elem_tag);
1147                         gtranslate(ser, a_v, elem_tag);
1148                         map[a_k] = a_v;
1149                 }
1150
1151         }
1152         else
1153         {
1154                 assert (ser->iomode() == sd_serialize);
1155                 typename std::map<K, V>::iterator iter = map.begin();
1156                 while (iter != map.end())
1157                 {
1158                         K &a_k = const_cast<K &>(iter->first);
1159                         V &a_v = const_cast<V &>(iter->second);
1160                         gtranslate(ser, a_k, elem_tag);
1161                         gtranslate(ser, a_v, elem_tag);
1162                         iter++;
1163                 }
1164         }
1165         ser->map_end();
1166 }
1167
1168 template <class K, class V, class L>
1169 struct multimap_translator
1170 {
1171         void operator()(SerializerBase *ser, std::multimap<K, V, L> &map, 
1172                         const char *tag = NULL, const char *elem_tag = NULL)
1173         {
1174                 unsigned long nelem = 0UL;
1175                 nelem = map.size();
1176                 ser->multimap_start(nelem, tag);
1177
1178                 if (ser->iomode() == sd_deserialize)
1179                 {
1180                         if (map.size())
1181                                 throw_ser_err(FILE__, __LINE__,"nonempty vector used to create");
1182
1183                         typename std::multimap<K, V, L>::iterator lastentry = map.begin();
1184                         //  cannot do any kind of bulk allocation with multimaps
1185                         for (unsigned int i = 0; i < nelem; ++i)
1186                         {
1187                                 typename std::multimap<K, V, L>::value_type mapentry;
1188                                 gtranslate(ser, mapentry, elem_tag);
1189                                 //  lastentry serves as a hint as to where the new value goes 
1190                                 //  (presumably near the last value inserted)
1191                                 //  not sure if this really makes things more efficient.
1192                                 lastentry = map.insert(lastentry, mapentry);
1193                         }
1194
1195                 }
1196                 else
1197                 {
1198                         assert (ser->iomode() == sd_serialize);
1199                         typename std::multimap<K, V, L>::iterator iter = map.begin();
1200                         while (iter != map.end())
1201                         {
1202                                 gtranslate(ser, *iter, elem_tag);
1203                                 iter++;
1204                         }
1205                 }
1206
1207                 ser->multimap_end();
1208         }
1209 };
1210
1211 template <class K, class V, class L>
1212 void translate_multimap(SerializerBase *ser, std::multimap<K, V, L> &map,
1213                 const char *tag = NULL, const char *elem_tag = NULL)
1214 {
1215         unsigned long nelem = 0UL;
1216         nelem = map.size();
1217         ser->multimap_start(nelem, tag);
1218
1219         if (ser->iomode() == sd_deserialize)
1220         {
1221                 if (map.size())
1222                         throw_ser_err(FILE__, __LINE__,"nonempty vector used to create");
1223
1224                 typename std::multimap<K, V, L>::iterator lastentry = map.begin();
1225                 //  cannot do any kind of bulk allocation with multimaps
1226                 for (unsigned int i = 0; i < nelem; ++i)
1227                 {
1228                         typename std::multimap<K, V, L>::value_type mapentry;
1229                         gtranslate(ser, mapentry, elem_tag);
1230                         //  lastentry serves as a hint as to where the new value goes 
1231                         //  (presumably near the last value inserted)
1232                         //  not sure if this really makes things more efficient.
1233                         lastentry = map.insert(lastentry, mapentry);
1234                 }
1235
1236         }
1237         else
1238         {
1239                 assert (ser->iomode() == sd_serialize);
1240                 typename std::multimap<K, V, L>::iterator iter = map.begin();
1241                 while (iter != map.end())
1242                 {
1243                         gtranslate(ser, *iter, elem_tag);
1244                         iter++;
1245                 }
1246         }
1247
1248         ser->multimap_end();
1249 }
1250
1251 template <class S, class K, class V>
1252 void translate_hash_map(S *ser, dyn_hash_map<K, V> &hash, 
1253                 const char *tag = NULL, const char *key_tag = NULL, const char *value_tag = NULL)
1254 {   
1255         fprintf(stderr, "%s[%d]:  welcome to translate_hash_map<%s, %s>()\n", 
1256                         __FILE__, __LINE__,
1257                         typeid(K).name(), typeid(V).name()); 
1258
1259         unsigned long nelem = 0UL;
1260         nelem = hash.size();
1261         ser->hash_map_start(nelem, tag);
1262
1263         if (ser->iomode() == sd_serialize) 
1264         {
1265                 typename dyn_hash_map<K,V>::iterator iter = hash.begin();
1266
1267                 while (iter != hash.end()) 
1268                 {
1269                         K k = iter->first;
1270                         V v = iter->second;
1271                         ser->translate_base(k, key_tag);
1272                         ser->translate_base(v, value_tag);
1273                         iter++;           
1274                 }
1275         }
1276         else 
1277         {
1278                 //  can we do some kind of preallocation here?
1279                 for (unsigned long i = 0; i < nelem; ++i) 
1280                 {
1281                         K k;
1282                         V v;
1283                         // zero out pointers to silence complaints about assigning
1284                         // new objects to non-NULL pointers
1285                         if (dyn_detail::boost::is_pointer<K>::value)
1286                                 memset(&k, 0, sizeof(K));
1287                         if (dyn_detail::boost::is_pointer<V>::value)
1288                                 memset(&v, 0, sizeof(V));
1289                         ser->translate_base(k, key_tag);
1290                         ser->translate_base(v, value_tag);
1291                         hash[k] = v;
1292                 }
1293         }
1294
1295         ser->hash_map_end();
1296 }
1297
1298 COMMON_EXPORT bool isBinary(Dyninst::SerializerBase *ser);
1299 COMMON_EXPORT bool isOutput(Dyninst::SerializerBase *ser);
1300
1301 typedef void NOTYPE_T;
1302
1303 template<typename T, typename T2 = typename dyn_detail::boost::is_enum<T>::type,
1304         typename T3 = typename dyn_detail::boost::is_base_of<Serializable, T>::type>
1305 class trans_adaptor {
1306    public:
1307       trans_adaptor()  {}
1308
1309       T * operator()(SerializerBase *ser, T & it, 
1310                           const char *tag = NULL, const char * /*tag2*/ = NULL)
1311       {
1312                  ser->translate_base(it, tag);
1313          return &it;
1314       }
1315 };
1316
1317 template <>
1318 class trans_adaptor<char *, dyn_detail::boost::false_type, 
1319           dyn_detail::boost::false_type> 
1320 {
1321    public:
1322       trans_adaptor()  {}
1323
1324       char * * operator()(SerializerBase *ser, char * & it, 
1325                           const char *tag = NULL, const char * /*tag2*/ = NULL)
1326       {
1327                   int len = it ? strlen(it) : 0;
1328                   ser->translate_base(it, len, tag);
1329                   return &it;
1330           }
1331 };
1332
1333 template<typename T>
1334 class trans_adaptor<T, dyn_detail::boost::false_type, 
1335           dyn_detail::boost::true_type> 
1336 {
1337    public:
1338       trans_adaptor()  {}
1339
1340       Serializable * operator()(SerializerBase *ser, T & it, const char *tag = NULL, 
1341             const char * /*tag2*/ = NULL)
1342       {
1343          //gtranslate(ser, it, tag);
1344
1345                   serialize_printf("%s[%d]:  translating serializable: %s\n", 
1346                                   FILE__, __LINE__, typeid(T).name());
1347
1348                   it.serialize(ser, tag);
1349
1350                   serialize_printf("%s[%d]:  translated serializable: %s\n", 
1351                                   FILE__, __LINE__, typeid(T).name());
1352
1353          return &it;
1354       }
1355 };
1356
1357 template<typename T>
1358 class trans_adaptor<T, dyn_detail::boost::true_type, 
1359           dyn_detail::boost::false_type> 
1360 {
1361    public:
1362       trans_adaptor()  {}
1363
1364       Serializable * operator()(SerializerBase *ser, T & it, const char *tag = NULL, 
1365             const char * /*tag2*/ = NULL)
1366       {
1367                   
1368                   if (sizeof(T) != sizeof(int)) 
1369                           fprintf(stderr, "%s[%d]:  enum size is %lu, not %lu\n",
1370                                           FILE__, __LINE__, sizeof(T), sizeof(int));
1371                   int e_int = (int) it;
1372           ser->translate_base(e_int, tag);
1373                   if (ser->isInput())
1374                           it = (T) e_int;
1375 #if 0
1376          //gtranslate(ser, it, tag);
1377
1378                   serialize_printf("%s[%d]:  translating serializable: %s\n", 
1379                                   FILE__, __LINE__, typeid(T).name());
1380
1381                   it.serialize(ser, tag);
1382
1383                   serialize_printf("%s[%d]:  translated serializable: %s\n", 
1384                                   FILE__, __LINE__, typeid(T).name());
1385 #endif
1386
1387                   return NULL;
1388          //return &it;
1389       }
1390 };
1391
1392 #if 0
1393 template<typename T>
1394 class trans_adaptor<std::vector<T>, dyn_detail::boost::false_type, 
1395           dyn_detail::boost::false_type> 
1396 {
1397    public:
1398       trans_adaptor() {}
1399
1400       std::vector<T> * operator()(SerializerBase *ser, std::vector<T> &v,  
1401             const char *tag = NULL, const char *tag2 = NULL) 
1402       {
1403          translate_vector(ser, v, tag, tag2);         //  maybe catch errors here?
1404          return &v;
1405       }
1406 };
1407 #endif
1408
1409 template <typename T, bool = dyn_detail::boost::is_base_of<Serializable, typename dyn_detail::boost::remove_pointer<T>::type>::value>
1410 class deref_adaptor 
1411 {
1412         public:
1413                 deref_adaptor() {}
1414
1415                 T * operator()(SerializerBase *sb, T &it, 
1416                                 const char *tag = NULL, const char *tag2 = NULL)
1417                 {
1418                         trans_adaptor<T> ta;
1419                         ta(sb, it, tag, tag2);
1420                         return &it;
1421                 }
1422 };
1423
1424 template <typename T>
1425 class deref_adaptor<T, true> 
1426 {
1427         public:
1428                 deref_adaptor() {}
1429
1430                 T * operator()(SerializerBase *sb, T *&it, 
1431                                 const char *tag = NULL, const char *tag2 = NULL)
1432                 {
1433                         //  need to allocate upon deserialize
1434                         if (!isOutput(sb))
1435                         {
1436                                 it = new T();
1437                         }
1438                         gtranslate(sb, *it, tag, tag2);
1439                         return it;
1440                 }
1441 };
1442
1443 template <typename T, typename T2 = typename dyn_detail::boost::is_pointer<T>::type, 
1444                  typename T3 = typename dyn_detail::boost::is_base_of<Serializable,
1445                  typename dyn_detail::boost::remove_pointer<T>::type>::type>
1446 class ptr_adaptor 
1447 {
1448         public:
1449                 ptr_adaptor() {}
1450
1451                 T * operator()(SerializerBase *sb, T &it, 
1452                                 const char *tag = NULL, const char *tag2 = NULL)
1453                 {
1454                         trans_adaptor<T> ta;
1455                         ta(sb, it, tag, tag2);
1456                         return &it;
1457                 }
1458 };
1459
1460 template <typename T>
1461 class ptr_adaptor<T, dyn_detail::boost::true_type, dyn_detail::boost::false_type> 
1462 {
1463         typedef typename dyn_detail::boost::remove_pointer<T>::type pointed_to_t;
1464
1465         public:
1466                 ptr_adaptor() {}
1467                 T * operator()(SerializerBase *sb, T &it, 
1468                                 const char *tag = NULL, const char *tag2 = NULL)
1469                 {
1470                         deref_adaptor<pointed_to_t> da;
1471                         da(sb, it, tag, tag2);
1472                         return &it;
1473                 }
1474 };
1475
1476 template <typename T>
1477 class ptr_adaptor<T, dyn_detail::boost::true_type, dyn_detail::boost::true_type> 
1478 {
1479         typedef typename dyn_detail::boost::remove_pointer<T>::type pointed_to_t;
1480         public:
1481                 ptr_adaptor() {}
1482                 T * operator()(SerializerBase *sb, T &it, 
1483                                 const char *tag = NULL, const char * = NULL)
1484                 {
1485                         if (!isOutput(sb))
1486                         {
1487                                 if (it)
1488                                         fprintf(stderr, "%s[%d]:  WARNING:  allocating to non-null pointer: %s\n", 
1489                                                         FILE__, __LINE__, typeid(T).name());
1490                                 serialize_printf("%s[%d]:  allocating new %s\n", 
1491                                                 FILE__, __LINE__, typeid(T).name());
1492
1493                                 it = new pointed_to_t();
1494                         }
1495
1496                         Serializable *res = NULL;
1497                         res = it->serialize(sb, tag);
1498
1499                         if (!isOutput(sb)) 
1500                         {
1501                                 T res_typed = dynamic_cast<T>(res);
1502
1503                                 if (res && !res_typed)
1504                                 {
1505                                         fprintf(stderr, "%s[%d]:  ERROR:  ser func allocated bad type object! not %s\n", 
1506                                                         FILE__, __LINE__, typeid(T).name());
1507                                 }
1508
1509                                 if (res_typed && (res_typed != it))
1510                                 {
1511                                         serialize_printf("%s[%d]:  serialize fn for %s reallocated object\n", 
1512                                                         FILE__, __LINE__, typeid(T).name());
1513                                         delete it;
1514                                         it = res_typed;
1515                                 }
1516                         }
1517
1518                         return &it;
1519                 }
1520 };
1521
1522 //  Another specialization:  do _not_ dereference any char *'s, they're special
1523 //  (maybe want to do this for all fundamental types)
1524 template <>
1525 class ptr_adaptor<char *, dyn_detail::boost::true_type, dyn_detail::boost::false_type> 
1526 {
1527         public:
1528                 ptr_adaptor() {}
1529                 char * * operator()(SerializerBase *sb, char * &it, 
1530                                 const char *tag = NULL, const char *tag2 = NULL)
1531                 {
1532                         trans_adaptor<char *> ta;
1533                         ta(sb, it, tag, tag2);
1534                         return &it;
1535                 }
1536 };
1537
1538 template <typename T, bool  = dyn_detail::boost::is_const<T>::value>
1539 class const_adaptor 
1540 {
1541         public:
1542                 const_adaptor() {}
1543
1544                 T *operator()(SerializerBase *sb, T &it, 
1545                                 const char *tag = 0, const char *tag2 = 0)
1546                 {
1547                         ptr_adaptor<T> ta;
1548                         T *itp = ta(sb, it, tag, tag2);
1549                         return itp;
1550                 }
1551 };
1552
1553 template <typename T>
1554 class const_adaptor<T, true>
1555 {
1556         typedef typename dyn_detail::boost::remove_cv<T>::type non_const_type;
1557
1558         public:
1559         const_adaptor() {}
1560
1561         T *operator()(SerializerBase *sb, T &it, 
1562                         const char *tag = 0, const char *tag2 = 0)
1563         {
1564                 gtranslate(sb, const_cast<non_const_type &>(it), tag, tag2);
1565                 return &it;
1566         }
1567 };
1568
1569 template <typename T>
1570 void gtranslate(SerializerBase *ser, T &it, 
1571                 const char *tag = NULL, const char *tag2 = NULL)
1572 {
1573    //fprintf(stderr, "%s[%d]:  welcome to gtranslate<%s, %s>(%p)\n",
1574    //      __FILE__, __LINE__,
1575    //      "SerializerBase",
1576    //      typeid(T).name(), &it);
1577
1578    const_adaptor<T> ta;
1579    T *itp = ta(ser, it, tag, tag2);
1580
1581    if (!itp) 
1582    {
1583       fprintf(stderr, "%s[%d]: translate adaptor failed to de/serialize\n", 
1584             __FILE__, __LINE__);
1585    }
1586 }
1587
1588 template <typename T>
1589 void gtranslate(SerializerBase *ser, std::vector<T> &it, 
1590                 const char *tag = NULL, const char *tag2 = NULL)
1591 {
1592         translate_vector(ser, it, tag, tag2);
1593 }
1594
1595 template <typename T, typename T2>
1596 void gtranslate(SerializerBase *ser, std::pair<T, T2> &it, 
1597                 const char *tag = NULL, const char *tag2 = NULL)
1598 {
1599         //translate_pair(ser, it, tag, tag2);
1600         pair_translator<T, T2> pt;
1601         pt(ser, it, tag, tag2);
1602 }
1603
1604 template <typename K, typename V, typename L>
1605 void gtranslate(SerializerBase *ser, std::multimap<K, V, L> &it, 
1606                 const char *tag = NULL, const char *tag2 = NULL)
1607 {
1608         translate_multimap(ser, it, tag, tag2);
1609 }
1610
1611 template <typename K, typename V>
1612 void gtranslate(SerializerBase *ser, dyn_hash_map<K, V> &it, 
1613                 const char *tag = NULL, const char *tag2 = NULL)
1614 {
1615         translate_dyn_hash_map(ser, it, tag, tag2);
1616 }
1617
1618 COMMON_EXPORT bool ifxml_start_element(SerializerBase *sb, const char *tag);
1619 COMMON_EXPORT bool ifxml_end_element(SerializerBase *sb, const char * /*tag*/);
1620 COMMON_EXPORT bool sb_is_input(SerializerBase *sb);
1621 COMMON_EXPORT bool sb_is_output(SerializerBase *sb);
1622
1623 template <typename T>
1624 void gtranslate(SerializerBase *ser, 
1625       T &it, 
1626       const char * (*to_str_func)(T), 
1627       const char *tag = NULL, 
1628       const char * /*tag2*/ = NULL)
1629 {
1630    assert(ser);
1631    int enum_int = 0;
1632    enum_int = (int) it;
1633
1634    if (!isBinary(ser)) 
1635    {
1636       assert(isOutput(ser));
1637
1638       // use human-readable tag
1639       const char *enum_tag = (*to_str_func)(it);
1640       std::string enum_tag_str(enum_tag);
1641       assert(enum_tag);
1642
1643       gtranslate(ser, enum_tag_str, tag, NULL);
1644    }
1645    else 
1646    {
1647       //  just in/output raw binary value 
1648       //gtranslate(ser, it);
1649       gtranslate(ser, enum_int, tag, NULL);
1650       it = (T) enum_int;
1651    }
1652 }
1653
1654 template <typename T>
1655 bool gtranslate_w_err(SerializerBase *ser, T &it, 
1656                 const char *tag = NULL, const char *tag2 = NULL)
1657 {
1658    try 
1659    {
1660       gtranslate(ser, it, tag, tag2);
1661    }
1662
1663    catch (const SerializerError &err_) 
1664    {
1665       fprintf(stderr, "%s[%d]:  gtranslate failed\n", __FILE__, __LINE__);
1666       printSerErr(err_);
1667       return false;
1668    }
1669    return true;
1670 }
1671
1672 } /* namespace Dyninst */
1673 #endif