windows build fixes and some more work on symtab serialization
[dyninst.git] / dynutil / h / Serialization.h
1
2 #if !defined (SERIALIZATION_PUBLIC_H)
3 #define SERIALIZATION_PUBLIC_H
4 //  Hopefully just a few definitions allowing for a public interface to 
5 //  serializing user-providede annotations
6
7 #include <stdio.h>
8 #include <assert.h>
9 #include <stdexcept>
10 #include <typeinfo>
11 #include <vector>
12 #include <assert.h>
13 #include "dyntypes.h"
14 #include "util.h"
15
16 namespace Dyninst {
17 //  SER_ERR("msg") -- an attempt at "graceful" failure.  If debug flag is set
18 //  it will assert, otherwise it throws...  leaving the "graceful" aspect
19 //  to the next (hopefully top-level) exception handler.
20
21
22 COMMON_EXPORT bool &serializer_debug_flag();
23
24 #define SER_ERR(cmsg) \
25    do { \
26       if (serializer_debug_flag()) { \
27          fprintf(stderr, "%s", cmsg); \
28          assert (0); \
29       } else { \
30          throw SerializerError(__FILE__, __LINE__, std::string(cmsg)); \
31       } \
32    } while (0)
33
34
35 class SerializerBase;
36
37
38 typedef enum {sd_serialize, sd_deserialize} iomode_t;
39 typedef bool (*deserialize_and_annotate_t)(SerializerBase *, void *parent);
40
41 bool addDeserializeFuncForType(deserialize_and_annotate_t, const std::type_info *);
42 deserialize_and_annotate_t getDeserializeFuncForType(const std::type_info *);
43
44 class SerializerError : public std::runtime_error {
45    //  SerializerError:  a small class that is thrown by serialization/deserialization
46    //  routines.  This exists as an attempt to standardize and simplify error handling
47    //  for ser-des routines that are possibly deeply nested.
48    //  Here's the rub:  we don't want stray, unhandled exceptions finding their way into
49    //  the larger system...  thus all entry points to serialization/deserialization need
50    //  to catch this exception to render it transparent to the rest of the system.
51
52    public:
53
54    typedef enum {
55       ser_err_unspecified,
56       ser_err_no_err,
57       ser_err_disabled
58    } SerializerErrorType;
59
60    private:
61
62    std::string file__;
63    int line__;
64    SerializerErrorType err__;
65
66    public:
67
68
69    COMMON_EXPORT SerializerError(const std::string &__file__, 
70          const int &__line__, 
71          const std::string &msg, 
72          SerializerErrorType __err__ = ser_err_unspecified) :
73       runtime_error(msg),
74       file__(__file__),
75       line__(__line__),
76       err__(__err__)
77    {}
78
79    COMMON_EXPORT virtual ~SerializerError() THROW {}
80
81    COMMON_EXPORT std::string file() const {return file__;}
82    COMMON_EXPORT int line() const {return line__;}
83    COMMON_EXPORT SerializerErrorType code() const {return err__;}
84 };
85
86
87 COMMON_EXPORT void printSerErr(const SerializerError &err);
88
89 class Serializable {
90    protected:
91       COMMON_EXPORT Serializable() {}
92       COMMON_EXPORT virtual ~Serializable() {}
93
94    public:
95       COMMON_EXPORT virtual void serialize(SerializerBase *,  const char * = NULL) THROW_SPEC(SerializerError) = 0;
96 };
97
98
99 template <class S, class T>
100 void translate_vector(S *ser, std::vector<T> &vec,
101       const char *tag = NULL, const char *elem_tag = NULL)
102 {
103    unsigned int nelem = vec.size();
104    ser->vector_start(nelem, tag);
105
106    if (ser->iomode() == sd_deserialize) 
107    {
108       if (vec.size())
109          SER_ERR("nonempty vector used to create");
110
111       //  zero size vectors are allowed
112       //  what it T is a complex type (with inheritance info)??
113       //  does resize() call default ctors, or should we do that
114       //  manually here? look this up.
115       if (nelem)
116          vec.resize(nelem);
117    }
118
119    for (unsigned int i = 0; i < vec.size(); ++i) 
120    {
121       T &t = vec[i];
122       gtranslate(ser, t, elem_tag);
123    }
124
125    ser->vector_end();
126 }
127
128
129 template <class S, class T>
130 void translate_vector(S *ser, std::vector<T *> &vec, 
131       const char *tag = NULL, const char *elem_tag = NULL) 
132 {
133    unsigned int nelem = vec.size();
134    ser->vector_start(nelem, tag);
135
136    if (ser->iomode() == sd_deserialize) 
137    {
138       if (vec.size()) 
139          SER_ERR("nonempty vector used to create");
140
141       //  zero size vectors are allowed
142       if (nelem) 
143       {
144          //  block-allocate array of underlying type, then assign to our vector
145          //  What happens if an individual elem is later deleted??
146          T *chunk_alloc = new T[nelem];
147          vec.resize(nelem);
148          for (unsigned int i = 0; i < nelem; ++i)
149             vec[i] = &(chunk_alloc[i]);
150       }
151    }
152
153    for (unsigned int i = 0; i < vec.size(); ++i) 
154    {
155       T &t = *(vec[i]);
156       gtranslate(ser, t, elem_tag);
157    }
158
159    ser->vector_end();
160 }
161
162 template <class S, class T>
163 void translate_vector(S *ser, std::vector<std::vector<T> > &vec, 
164       const char *tag = NULL, const char *elem_tag = NULL) 
165 {
166    fprintf(stderr, "%s[%d]:  welcome to translate vector of vectors\n", 
167            __FILE__, __LINE__);
168
169    unsigned int nelem = vec.size();
170    ser->vector_start(nelem, tag);
171    if (ser->iomode() == sd_deserialize) 
172    {
173       if (vec.size())
174          SER_ERR("nonempty vector used to create");
175
176       //  zero size vectors are allowed
177       //  what it T is a complex type (with inheritance info)??
178       //  does resize() call default ctors, or should we do that
179       //  manually here? look this up.
180       if (nelem)
181          vec.resize(nelem);
182    }
183
184    for (unsigned int i = 0; i < vec.size(); ++i) 
185    {
186       std::vector<T> &tv = vec[i];
187       translate_vector(ser,tv, tag, elem_tag);
188    }
189
190    ser->vector_end();
191 }
192
193 template <class S, class K, class V>
194 void translate_hash_map(S *ser, dyn_hash_map<K, V> &hash, 
195       const char *tag = NULL, const char *key_tag = NULL, const char *value_tag = NULL)
196 {   
197    fprintf(stderr, "%s[%d]:  welcome to translate_hash_map<%s, %s>()\n", 
198            __FILE__, __LINE__,
199            typeid(K).name(), typeid(V).name()); 
200
201    unsigned int nelem = hash.size();
202    ser->hash_map_start(nelem, tag);
203    fprintf(stderr, "%s[%d]:  after hash_map start, mode = %sserialize\n", 
204            __FILE__, __LINE__, ser->iomode() == sd_serialize ? "" : "de"); 
205
206    if (ser->iomode() == sd_serialize) 
207    {
208       typename dyn_hash_map<K,V>::iterator iter = hash.begin();
209       fprintf(stderr, "%s[%d]:  about to serialize hash with %d elements\n", 
210               __FILE__, __LINE__, hash.size());
211
212       while (iter != hash.end()) 
213       {
214          K k = iter->first;
215          V v = iter->second;
216          ser->translate_base(k, key_tag);
217          ser->translate_base(v, value_tag);
218          iter++;           
219       }
220    }
221    else 
222    {
223       //  can we do some kind of preallocation here?
224       for (unsigned int i = 0; i < nelem; ++i) 
225       {
226          K k;
227          V v;
228          ser->translate_base(k, key_tag);
229          ser->translate_base(v, value_tag);
230          hash[k] = v;
231       }
232    }
233
234    ser->hash_map_end();
235 }
236
237 template <class S, class K, class V>
238 void translate_hash_map(S *ser, dyn_hash_map<K, V *> &hash,
239       const char *tag = NULL, const char *key_tag = NULL, const char *value_tag = NULL)
240 {
241    fprintf(stderr, "%s[%d]:  welcome to translate_hash_map<%s, %s*>()\n", 
242          __FILE__, __LINE__,
243          typeid(K).name(), typeid(V).name());
244
245    unsigned int nelem = hash.size();
246    ser->hash_map_start(nelem, tag);
247
248    fprintf(stderr, "%s[%d]:  after hash_map start, mode = %sserialize\n", 
249          __FILE__, __LINE__, ser->iomode() == sd_serialize ? "" : "de");
250
251    if (ser->iomode() == sd_serialize) 
252    {
253       typename dyn_hash_map<K,V *>::iterator iter = hash.begin();
254
255       while (iter != hash.end()) 
256       {
257          K k = iter->first;
258          V *v = iter->second;
259          ser->translate_base(k, key_tag);
260          ser->translate_base(*v, value_tag);
261          iter++;
262       }
263    }
264    else 
265    {
266       //  can we do some kind of preallocation here?
267       for (unsigned int i = 0; i < nelem; ++i) 
268       {
269          K k;
270          V *v = new V();
271          ser->translate_base(k, key_tag);
272          ser->translate_base(*v, value_tag);
273          hash[k] = v;
274       }
275    }
276    ser->hash_map_end();
277 }
278
279 template <class S, class K, class V>
280 void translate_hash_map(S *ser, dyn_hash_map<K, char *> &hash,
281       const char *tag = NULL, const char *key_tag = NULL, const char *value_tag = NULL)
282 {
283    //  THIS SPECIALIZATION DOES NOT WORK CORRECTLY (YET)
284    fprintf(stderr, "%s[%d]:  welcome to translate_hash_map<%s, %s*>()\n", 
285          __FILE__, __LINE__,
286          typeid(K).name(), typeid(V).name());
287
288    unsigned int nelem = hash.size();
289    ser->hash_map_start(nelem, tag);
290
291    fprintf(stderr, "%s[%d]:  after hash_map start, mode = %sserialize\n", 
292          __FILE__, __LINE__, ser->iomode() == sd_serialize ? "" : "de");
293
294    if (ser->iomode() == sd_serialize) 
295    {
296       typename dyn_hash_map<K,V *>::iterator iter = hash.begin();
297       
298       while (iter != hash.end()) 
299       {
300          K k = iter->first;
301          V v = iter->second;
302          ser->translate_base(k, key_tag);
303          ser->translate_base(v, value_tag);
304          iter++;
305       }
306    }
307    else 
308    {
309       //  can we do some kind of preallocation here?
310       for (unsigned int i = 0; i < nelem; ++i) 
311       {
312          K k;
313          V v;
314          ser->translate_base(k, key_tag);
315          ser->translate_base(*v, value_tag);
316          hash[k] = v;
317       }
318    }
319    ser->hash_map_end();
320 }
321
322
323 COMMON_EXPORT void trans_adapt(SerializerBase *ser, Serializable &it,  const char *tag);
324 COMMON_EXPORT void trans_adapt(SerializerBase *ser, Serializable *itp,  const char *tag);
325
326 COMMON_EXPORT void trans_adapt(SerializerBase *ser, bool &it,  const char *tag);
327 COMMON_EXPORT void trans_adapt(SerializerBase *ser, int &it,  const char *tag);
328 COMMON_EXPORT void trans_adapt(SerializerBase *ser, unsigned int &it,  const char *tag);
329 COMMON_EXPORT void trans_adapt(SerializerBase *ser, long &it,  const char *tag);
330 COMMON_EXPORT void trans_adapt(SerializerBase *ser, unsigned long &it,  const char *tag);
331 COMMON_EXPORT void trans_adapt(SerializerBase *ser, char &it,  const char *tag);
332 COMMON_EXPORT void trans_adapt(SerializerBase *ser, char *&it,  const char *tag);
333 COMMON_EXPORT void trans_adapt(SerializerBase *ser, std::string &it,  const char *tag);
334 COMMON_EXPORT void trans_adapt(SerializerBase *ser, float &it,  const char *tag);
335 COMMON_EXPORT void trans_adapt(SerializerBase *ser, double &it,  const char *tag);
336
337 COMMON_EXPORT bool isBinary(Dyninst::SerializerBase *ser);
338 COMMON_EXPORT bool isOutput(Dyninst::SerializerBase *ser);
339
340 typedef void NOTYPE_T;
341 template<class S, class T, class T2 = NOTYPE_T>
342 class trans_adaptor {
343    public:
344       trans_adaptor() 
345       {
346          //fprintf(stderr, "%s[%d]:  trans_adaptor  -- general\n", __FILE__, __LINE__);
347       } 
348
349       T * operator()(S *ser, T & it, const char *tag = NULL, const char * /*tag2*/ = NULL)
350       {
351          trans_adapt(ser, it, tag);
352          return &it;
353       }
354 };
355
356 template<class S, class T2>
357 class trans_adaptor<S, Serializable, T2> {
358    public:
359       trans_adaptor() 
360       {
361          fprintf(stderr, "%s[%d]:  trans_adaptor  -- general\n", __FILE__, __LINE__);
362       } 
363
364       Serializable * operator()(S *ser, Serializable & it, const char *tag = NULL, 
365             const char * /*tag2*/ = NULL)
366       {
367          gtranslate(ser, it, tag);
368          return &it;
369       }
370 };
371
372 template<class S, class T, class TT2>
373 class trans_adaptor<S, std::vector<T>, TT2 > {
374    public:
375       trans_adaptor()
376       {
377          fprintf(stderr, "%s[%d]:  trans_adaptor  -- vectorl\n", __FILE__, __LINE__);
378       }
379
380       std::vector<T> * operator()(S *ser, std::vector<T> &v, const char *tag = NULL, 
381             const char *tag2 = NULL) 
382       {
383          translate_vector(ser, v, tag, tag2);         //  maybe catch errors here?
384          return &v;
385       }
386 };
387
388 template<class S, class T, class TT2>
389 class trans_adaptor<S, std::vector<T *>, TT2>  {
390    public: 
391       trans_adaptor() 
392       {
393          fprintf(stderr, "%s[%d]:  trans_adaptor  -- vector of ptrs\n", __FILE__, __LINE__);
394       }
395
396       std::vector<T*> * operator()(S *ser, std::vector<T *> &v, const char *tag = NULL, 
397             const char *tag2 = NULL) 
398       {
399          translate_vector(ser, v, tag, tag2);
400          //  maybe catch errors here?
401          return &v;
402       }
403 };
404
405 #if 0
406 template<class T, class ANNO_NAME, bool, annotation_implementation_t>
407 class Annotatable<T, ANNO_NAME,bool, annotation_implementation_t>;
408 #endif
409    
410 #if 0
411 I really really wish this worked, maybe it still can given some more pounding
412
413 template<class S, class T, class ANNO_NAME, bool SERIALIZABLE, annotation_implementation_t IMPL>
414 class trans_adaptor<S, 
415       Annotatable<T, 
416       ANNO_NAME, 
417       SERIALIZABLE,
418       IMPL> &>  {
419    public: 
420       trans_adaptor() 
421       {
422          fprintf(stderr, "%s[%d]:  trans_adaptor  -- annotatable<%s, %s, %s>\n", 
423                __FILE__, __LINE__, typeid(T).name(), typeid(ANNO_NAME).name(),
424                SERIALIZABLE ? "true" : "false");
425       }
426
427       Annotatable<T, ANNO_NAME, SERIALIZABLE, IMPL> * operator()(S *ser, 
428             Annotatable<T, ANNO_NAME, SERIALIZABLE, IMPL> &v, const char *tag = NULL, 
429             const char *tag2 = NULL) 
430       {
431           if (!SERIALIZABLE) 
432           {
433              fprintf(stderr, "%s[%d]:  Annotatable<%s, %s, %s>, not serializable\n", 
434                    __FILE__, __LINE__, typeid(T).name(), typeid(ANNO_NAME).name(),
435                    SERIALIZABLE ? "true" : "false");
436              return NULL;
437           }
438
439           int nelem = v.size();
440
441           if (0 == nelem) 
442           {
443              fprintf(stderr, "%s[%d]:  Annotatable<%s, %s, %s>, no annotations\n", 
444                    __FILE__, __LINE__, typeid(T).name(), typeid(ANNO_NAME).name(),
445                    SERIALIZABLE ? "true" : "false");
446              return NULL;
447           }
448
449           //  data structure must exist since size > 0
450
451           std::vector<T> &anno_vec = v.getDataStructure();
452
453           //  But is this OK??  (This goes around the usual annotations interface)
454           //  probably not, but let's see if it works anyways
455
456           fprintf(stderr, "%s[%d]:  WARNING:  This may not be kosher -- circumventing the anotations interface, think on this\n", __FILE__, __LINE__);
457           translate_vector(ser, anno_vec, tag, tag2);
458
459          //  maybe catch errors here?
460          return &v;
461       }
462 };
463 #endif
464
465 template <class S, class T>
466 void gtranslate(S *ser, T &it, const char *tag = NULL, const char *tag2 = NULL)
467 {
468    //fprintf(stderr, "%s[%d]:  welcome to gtranslate<%s, %s>(%p)\n",
469    //      __FILE__, __LINE__,
470    //      "SerializerBase",
471    //      typeid(T).name(), &it);
472
473    //  Maybe just need to do try/catch here since the template mapping may 
474    //  change the type of return value thru template specialization
475
476    trans_adaptor<S, T> ta;
477    //fprintf(stderr, "%s[%d]: gtranslate: before operation\n", __FILE__, __LINE__);
478
479    T *itp = ta(ser, it, tag, tag2);
480
481    if (!itp) 
482    {
483       fprintf(stderr, "%s[%d]: translate adaptor failed to de/serialize\n", 
484             __FILE__, __LINE__);
485    }
486 }
487
488 COMMON_EXPORT bool ifxml_start_element(SerializerBase *sb, const char *tag);
489 COMMON_EXPORT bool ifxml_end_element(SerializerBase *sb, const char * /*tag*/);
490
491 //template<class T> class SerializerBin<T>;
492 //template<class T> class SerializerXML<T>;
493
494 COMMON_EXPORT bool sb_is_input(SerializerBase *sb);
495 COMMON_EXPORT bool sb_is_output(SerializerBase *sb);
496
497 #if 0
498 template <class T>
499 bool ifinput(bool (*f)(SerializerBase *, T*), SerializerBase *sb, T *itp)
500 {
501    if (!sb_is_input(sb))
502       return false;
503
504
505    return (*f)(sb, itp);
506 }
507
508 template <class T>
509 bool ifoutput(bool (*f)(SerializerBase *, T*), SerializerBase *sb, T *itp)
510 {
511    if (!sb_is_output(sb))
512       return false;
513
514    return (*f)(sb, itp);
515 }
516
517 template <class T>
518 bool ifbin(bool (*f)(SerializerBase *, T*), SerializerBase *sb, T *itp)
519 {
520    SerializerBin *sbin = dynamic_cast<SerializerBin *>(sb);
521
522    if (!sbin)
523       return false;
524
525    return (*f)(sbin, itp);
526 }
527
528 template <class T>
529 bool ifxml(bool (*f)(SerializerBase *, T*), SerializerBase *sb, T *itp)
530 {
531    SerializerXML *sxml = dynamic_cast<SerializerXML *>(sb);
532
533    if (!sxml)
534       return false;
535
536    return (*f)(sxml, itp);
537 }
538 #endif
539 #if 0
540 {
541    fprintf(stderr, "%s[%d]:  welcome to gtranslate<%s, %s>(%p)\n",
542          __FILE__, __LINE__,
543          "SerializerBase",
544          typeid(TT).name(), &it);
545
546    //  Maybe just need to do try/catch here since the template mapping may 
547    //  change the type of return value thru template specialization
548    assert(use_func);
549    (*use_func)(ser, it);
550 }
551
552 template<class S, class TT>
553 void trans_enum(S *ser, TT &it, std::vector<std::string> *enum_tags_ptr) 
554 {
555    assert(enum_tags_ptr);
556    std::vector<std::string> &enum_tags = *enum_tags_ptr;
557    assert(it < enum_tags.size());
558    unsigned int enum_int = (unsigned int) it;
559    gtranslate(ser, it);
560 }
561 #endif
562
563
564 template <class S, class T>
565 void gtranslate(S *ser, 
566       T &it, 
567       const char * (*to_str_func)(T), 
568       const char *tag = NULL, 
569       const char * /*tag2*/ = NULL)
570 {
571    assert(ser);
572    int enum_int = (int) it;
573
574    if (!isBinary(ser)) 
575    {
576       assert(isOutput(ser));
577
578       // use human-readable tag
579       const char *enum_tag = (*to_str_func)(it);
580       std::string enum_tag_str(enum_tag);
581       assert(enum_tag);
582
583       gtranslate(ser, enum_tag_str, tag, NULL);
584    }
585    else 
586    {
587       //  just in/output raw binary value 
588       gtranslate(ser, enum_int, tag, NULL);
589       it = (T) enum_int;
590    }
591 }
592
593 class SerializerError;
594
595 template <class S, class T>
596 bool gtranslate_w_err(S *ser, T&it, const char *tag = NULL, const char *tag2 = NULL)
597 {
598
599    try 
600    {
601       gtranslate(ser, it, tag, tag2);
602    }
603
604    catch (const SerializerError &err_) 
605    {
606       fprintf(stderr, "%s[%d]:  gtranslate failed\n", __FILE__, __LINE__);
607       printSerErr(err_);
608       return false;
609    }
610    return true;
611 }
612
613 //  These are for testing purposes -- do not use elsewhere
614 //  Must deallocate serializer that is returned when done.
615 #if 0
616 SerializerBase *nonpublic_make_bin_serializer(std::string file);
617 SerializerBase *nonpublic_make_bin_deserializer(std::string file);
618 void nonpublic_free_bin_serializer(SerializerBase *sb);
619 #endif
620 #if 0
621 template <class T> class SerializerBin;
622
623 template <class T>
624 inline SerializerBase *nonpublic_make_bin_serializer(T *t, std::string file)
625 {
626         SerializerBin<T> *ser;
627         ser = new SerializerBin<T>(t, "SerializerBin", file, sd_serialize, true);
628         return ser;
629 }
630
631 template <class T>
632 inline void nonpublic_free_bin_serializer(SerializerBase *sb)
633 {
634         SerializerBin<T> *sbin = dynamic_cast<SerializerBin<T> *>(sb);
635         if (sbin)
636         {
637                 delete(sbin);
638         }
639         else
640                 fprintf(stderr, "%s[%d]:  FIXME\n", FILE__, __LINE__);
641 }
642
643 template <class T>
644 inline SerializerBase *nonpublic_make_bin_deserializer(T *t,std::string file)
645 {
646         SerializerBin<T> *ser;
647         ser = new SerializerBin<T>(t, "DeserializerBin", file, sd_deserialize, true);
648         return ser;
649 }
650 #endif
651
652 } /* namespace Dyninst */
653 #endif