These are the windows fixes that I previously alluded to, combined with
[dyninst.git] / common / h / serialize.h
1
2 /*
3  * Copyright (c) 1996-2007 Barton P. Miller
4  * 
5  * We provide the Paradyn Parallel Performance Tools (below
6  * described as "Paradyn") on an AS IS basis, and do not warrant its
7  * validity or performance.  We reserve the right to update, modify,
8  * or discontinue this software at any time.  We shall have no
9  * obligation to supply such updates or modifications or any other
10  * form of support to you.
11  * 
12  * By your use of Paradyn, you understand and agree that we (or any
13  * other person or entity with proprietary rights in Paradyn) are
14  * under no obligation to provide either maintenance services,
15  * update services, notices of latent defects, or correction of
16  * defects for Paradyn.
17  * 
18  * This library is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU Lesser General Public
20  * License as published by the Free Software Foundation; either
21  * version 2.1 of the License, or (at your option) any later version.
22  * 
23  * This library is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26  * Lesser General Public License for more details.
27  * 
28  * You should have received a copy of the GNU Lesser General Public
29  * License along with this library; if not, write to the Free Software
30  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
31  */
32
33 #ifndef __SERDES_H__
34 #define __SERDES_H__
35 #include <string>
36 #include <vector>
37 #include <map>
38 #include <stdexcept>
39 #include <stdio.h>
40 #include <libxml/xmlwriter.h>
41
42 #include "common/h/headers.h"
43 #include "common/h/Types.h"
44 #include "common/h/sha1.h"
45 #include "common/h/pathName.h"
46
47 #define CACHE_DIR_VAR "DYNINST_CACHE_DIR"
48 #define DEFAULT_DYNINST_DIR ".dyninstAPI"
49 #define DEFAULT_CACHE_DIR "caches"
50 #define CACHE_MAGIC 0x555
51 #define CACHE_PREFIX "cache_"
52
53 #ifndef PATH_MAX
54 #define PATH_MAX 512
55 #endif
56
57
58 DLLEXPORT bool &serializer_debug_flag();
59 //  SER_ERR("msg") -- an attempt at "graceful" failure.  If debug flag is set
60 //  it will assert, otherwise it throws...  leaving the "graceful" aspect
61 //  to the next (hopefully top-level) exception handler.
62
63 #define SER_ERR(cmsg) if (serializer_debug_flag()) assert (0 && cmsg); \
64                       else throw SerializerError(FILE__, __LINE__, std::string(cmsg))
65
66 //  SER_CATCH("string") is mostly for debugging...  it is just a default catch-block
67 //  that prints out a message and then throws another exception.  The idea is that,
68 //  when an exception is thrown, even though it comes with an informative message,
69 //  it is even more informative to know that call-path that produced it.
70 //  SER_CATCH provides a fairly non-intrusive way to add this functionality
71
72 #define SER_CATCH(x) catch (const SerializerError &err) { \
73    fprintf(stderr, "%s[%d]: %s from %s[%d]\n", FILE__, __LINE__, \
74             err.what(), err.file().c_str(), err.line()); \
75    SER_ERR(x); }
76
77 void DLLEXPORT serialize_debug_init();
78
79 typedef enum {sd_serialize, sd_deserialize} iomode_t;
80
81 class SerializerError : public std::runtime_error {
82    //  SerializerError:  a small class that is thrown by serialization/deserialization
83    //  routines.  This exists as an attempt to standardize and simplify error handling
84    //  for ser-des routines that are possibly deeply nested.
85    //  Here's the rub:  we don't want stray, unhandled exceptions finding their way into
86    //  the larger system...  thus all entry points to serialization/deserialization need
87    //  to catch this exception to render it transparent to the rest of the system.
88
89     std::string file__;
90     int line__;
91
92   public:
93
94   SerializerError(const std::string &__file__, const int &__line__, const std::string &msg) :
95      runtime_error(msg),
96      file__(__file__),
97      line__(__line__) {}
98   virtual ~SerializerError() throw() {}
99
100   std::string file() const {return file__;}
101   int line() const {return line__;}
102 };
103
104 class DLLEXPORT SerDes {
105    //  SerDes is a base class that provides generic serialization/deserialization
106    //  access primitives and a common interface, (a toolbox, if you will).
107    //  It is specialized (currently) by SerDesBin and SerDesXML, which implement the 
108    //  actual low-level ser-des routines 
109
110   public:
111
112     SerDes(std::string fname, iomode_t mode, bool verbose = false) :
113        iomode_(mode), noisy(verbose) {
114           char file_path[PATH_MAX];
115           if (!resolve_file_path(fname.c_str(), file_path)) {
116              char msg[128];
117              sprintf(msg, "failed to resolve path for '%s'\n", fname.c_str());
118              SER_ERR(msg);
119           }
120           filename = std::string(file_path);
121           serialize_debug_init();
122        }
123     virtual ~SerDes() {}
124
125     virtual void file_start(std::string &/*full_file_path*/) {}
126     virtual void vector_start(unsigned int &size, const char *tag = NULL) throw(SerializerError) = 0;
127     virtual void vector_end() = 0;
128     virtual void multimap_start(unsigned int &size, const char *tag = NULL) throw(SerializerError) = 0;
129     virtual void annotation_start(const char *string_id, const char *tag = NULL) = 0;
130     virtual void annotation_end() = 0;
131
132     virtual void multimap_end() = 0;
133     virtual void translate(bool &param, const char *tag = NULL) = 0;
134     virtual void translate(char &param, const char *tag = NULL) = 0;
135     virtual void translate(int &param, const char *tag = NULL) = 0;
136     virtual void translate(unsigned int &param, const char *tag = NULL) = 0;
137 #if 0
138     virtual void translate(OFFSET &param, const char *tag = NULL) = 0;
139     virtual void translate(pdstring &param, const char *tag = NULL) = 0;
140 #endif
141     virtual void translate(Address &param, const char *tag = NULL) = 0;
142     virtual void translate(const char * &param, int bufsize = 0, const char *tag = NULL) = 0;
143     virtual void translate(std::string &param, const char *tag = NULL) = 0;
144     virtual void translate(std::vector<std::string> &param, const char *tag = NULL,
145                            const char *elem_tag = NULL) = 0;
146
147     iomode_t iomode() {return iomode_;}
148   protected:
149     std::string filename;
150     iomode_t iomode_;
151   public:
152     bool noisy;
153 };
154
155 class DLLEXPORT SerDesXML : public SerDes {
156   public:
157
158     SerDesXML(std::string fname, iomode_t mode, bool verbose = false);
159     virtual ~SerDesXML();
160
161     virtual void vector_start(unsigned int &size, const char *tag = NULL) throw(SerializerError);
162     virtual void vector_end();
163     virtual void multimap_start(unsigned int &size, const char *tag = NULL) throw(SerializerError);
164     virtual void multimap_end();
165     virtual void annotation_start(const char *string_id, const char *tag = NULL);
166     virtual void annotation_end();
167     virtual void translate(bool &param, const char *tag = NULL);
168     virtual void translate(char &param, const char *tag = NULL);
169     virtual void translate(int &param, const char *tag = NULL);
170     virtual void translate(unsigned int &param, const char *tag = NULL);
171 #if 0
172     virtual void translate(OFFSET &param, const char *tag = NULL);
173     virtual void translate(pdstring &param, const char *tag = NULL);
174 #endif
175     virtual void translate(Address &param, const char *tag = NULL);
176     virtual void translate(const char * &param, int bufsize = 0, const char *tag = NULL);
177     virtual void translate(std::string &param, const char *tag = NULL);
178     virtual void translate(std::vector<std::string> &param, const char *tag = NULL,
179                            const char *elem_tag = NULL);
180     void start_element(const char *tag);
181     void end_element();
182     void xml_value(const char *val, const char *tag);
183
184   protected:
185     xmlTextWriterPtr writer;
186 };
187
188
189 class DLLEXPORT SerDesBin : public SerDes {
190
191   typedef struct {
192      unsigned int cache_magic;
193      unsigned int source_file_size; //  if size is different, don't bother with checksum
194      char sha1[SHA1_DIGEST_LEN];
195   } cache_header_t;
196
197     FILE *f;
198
199   public:
200
201     SerDesBin(std::string fname, iomode_t mode, bool verbose = false);
202     virtual ~SerDesBin();
203
204     static bool validCacheExistsFor(std::string full_file_path);
205     void readHeaderAndVerify(std::string full_file_path, std::string cache_name);
206     void writeHeaderPreamble(std::string full_file_path, std::string cache_name);
207
208     virtual void file_start(std::string &full_file_path);
209     virtual void vector_start(unsigned int &size, const char *tag = NULL) throw(SerializerError);
210     virtual void vector_end();
211     virtual void multimap_start(unsigned int &size, const char *tag = NULL) throw(SerializerError);
212     virtual void multimap_end();
213     virtual void annotation_start(const char *string_id, const char *tag = NULL);
214     virtual void annotation_end();
215     virtual void translate(bool &param, const char *tag = NULL);
216     virtual void translate(char &param, const char *tag = NULL);
217     virtual void translate(int &param, const char *tag = NULL);
218     virtual void translate(unsigned int &param, const char *tag = NULL);
219 #if 0
220     virtual void translate(OFFSET &param, const char *tag = NULL);
221     virtual void translate(pdstring &param, const char *tag = NULL);
222 #endif
223     virtual void translate(Address &param, const char *tag = NULL);
224     virtual void translate(const char * &param, int bufsize = 0, const char *tag = NULL);
225     virtual void translate(std::string &param, const char *tag = NULL);
226     virtual void translate(std::vector<std::string> &param, const char *tag = NULL,
227                            const char *elem_tag = NULL);
228
229   private:
230
231     static bool getDefaultCacheDir(std::string &cache_dir);
232     static bool resolveCachePath(std::string fname, std::string &cache_name);
233     static bool verifyChecksum(std::string &filename, const char comp_checksum[SHA1_DIGEST_LEN]);
234     static bool cacheFileExists(std::string fname);
235     static bool invalidateCache(std::string cache_name);
236 };
237
238 #if 0 // SERIALIZE
239 class SerializeCommonBase {
240   public:
241      virtual bool translate_annotation(void *anno, const char *name) = 0;
242
243   protected:
244      SerializeCommonBase() {};
245      virtual ~SerializeCommonBase() {};
246 };
247 #endif
248
249 template <class S, class T>
250 void translate_vector(S *ser, std::vector<T> &vec, 
251                       const char *tag = NULL, const char *elem_tag = NULL) 
252 {
253    unsigned int nelem = vec.size();
254    ser->vector_start(nelem, tag);
255    if (ser->iomode() == sd_deserialize) {
256       if (vec.size()) 
257          SER_ERR("nonempty vector used to create");
258       //  zero size vectors are allowed
259       //  what it T is a complex type (with inheritance info)??
260       //  does resize() call default ctors, or should we do that
261       //  manually here? look this up.
262       if (nelem)
263          vec.resize(nelem);
264    }
265       
266    for (unsigned int i = 0; i < vec.size(); ++i) {
267     T &t = vec[i];
268     ser->translate_base(t, elem_tag);
269    }
270    ser->vector_end();
271 }
272
273 template <class S, class T>
274 void translate_vector(S *ser, std::vector<T *> &vec, 
275                       const char *tag = NULL, const char *elem_tag = NULL) 
276 {
277    unsigned int nelem = vec.size();
278    ser->vector_start(nelem, tag);
279    if (ser->iomode() == sd_deserialize) {
280       if (vec.size()) 
281          SER_ERR("nonempty vector used to create");
282       //  zero size vectors are allowed
283       if (nelem) {
284          //  block-allocate array of underlying type, then assign to our vector
285          //  What happens if an individual elem is later deleted??
286          T *chunk_alloc = new T[nelem];
287          vec.resize(nelem);
288          for (unsigned int i = 0; i < nelem; ++i) 
289              vec[i] = &(chunk_alloc[i]);
290       }
291    }
292
293    for (unsigned int i = 0; i < vec.size(); ++i) {
294     T &t = *(vec[i]);
295     ser->translate_base(t, elem_tag);
296    }
297    ser->vector_end();
298 }
299
300 template <class S, class K, class V, class CMP>
301 void translate_multimap(S *ser, std::multimap<K, V, CMP> &mm, 
302       const char *tag = NULL, const char *key_tag = NULL, const char *value_tag = NULL)
303 {
304    unsigned int nelem = mm.size();
305    ser->multimap_start(nelem, tag);
306    if (ser->iomode() == sd_serialize) {
307       typename std::multimap<K,V,CMP>::iterator iter = mm.begin();
308       while (iter != mm.end()) {
309          K k = iter->first;
310          V v = iter->second;
311          ser->translate_base(k, key_tag);
312          ser->translate_base(v, value_tag);
313       }
314    }
315    else {
316       for (unsigned int i = 0; i < nelem; ++i) {
317          K k;
318          V v;
319          ser->translate_base(k, key_tag);
320          ser->translate_base(v, value_tag);
321          mm[k] = v;
322       }
323    }
324    ser->multimap_end();
325 }
326
327 #if 0
328 template <class S, class T>
329 void translate_annotation(S *ser, T &it, const char *anno_str, const char *tag = NULL)
330 {
331    ser->annotation_start(anno_str, tag);
332    if (ser->iomode() == sd_serialize) {
333       ser->translate_base(it, tag);
334    }
335    ser->annotation_end();
336 }
337
338 template <class S, class T>
339 void translate_annotation(S *ser, T *it, const char *anno_str, const char *tag = NULL)
340 {
341    ser->annotation_start(anno_str, tag);
342    if (ser->iomode() == sd_serialize) {
343       ser->translate_base(*it, tag);
344    }
345    ser->annotation_end();
346 }
347 #endif
348 #endif