These are the windows fixes that I previously alluded to, combined with
[dyninst.git] / dynutil / h / Annotatable.h
1 /*
2  * Copyright (c) 1996-2004 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  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 // $Id: Annotatable.h,v 1.9 2008/05/09 00:25:38 jaw Exp $
43
44 #ifndef _ANNOTATABLE_
45 #define _ANNOTATABLE_
46
47 #include <cstring>
48 #include <vector>
49 #include <string>
50 #include <typeinfo>
51 #include <assert.h>
52 #include "dyntypes.h"
53 #include "util.h"
54
55 class DLLEXPORT_COMMON AnnotatableBase;
56
57 #if !defined(_MSC_VER)
58 namespace __gnu_cxx {
59    template<> struct hash<AnnotatableBase *> {
60       hash<char*> h;
61       unsigned operator()(const AnnotatableBase *b) const {
62          return ::Dyninst::addrHashCommon((Dyninst::Address)b);
63       };
64    };
65 }
66 #endif
67
68 using std::vector;
69
70
71 class DLLEXPORT_COMMON AnnotatableBase
72 {
73    protected:
74       AnnotatableBase();
75       ~AnnotatableBase() {
76       }
77       static int number;
78       static hash_map<std::string, int> annotationTypes;
79       static hash_map<std::string, int> metadataTypes;
80       static int metadataNum;
81
82    public:
83
84       static int createAnnotationType(std::string &name);
85       static int getAnnotationType(std::string &name);
86       static int getOrCreateAnnotationType(std::string &anno_name) {
87          int anno_type = getAnnotationType(anno_name);
88          if (anno_type == -1) {
89             anno_type = createAnnotationType(anno_name);
90           //  fprintf(stderr, "%s[%d]:  created annotation type %s/%d\n", 
91            //       FILE__, __LINE__, anno_name.c_str(), anno_type);
92          }
93          return anno_type;
94       }
95 #if 0
96       virtual int createMetadata(std::string &name);
97       virtual int getMetadata(std::string &name);
98 #endif
99
100 };
101
102 template<class T>
103 class AnnotationSet {
104    //  T is a container, so far, always a vector of something else
105
106    //typedef hash_map<char *, as_id_map_t*> obj_map_t;
107    //typedef hash_map<AnnotatableBase *, as_id_map_t*> obj_map_t;
108
109    typedef hash_map<int, T*> as_id_map_t;
110    typedef hash_map<char *, as_id_map_t> obj_map_t;
111    static obj_map_t sets_by_obj;
112
113    public:
114    AnnotationSet() {}
115    ~AnnotationSet() {}
116
117    static T *findAnnotationSet(char  *b, int anno_id) 
118    {
119       typename obj_map_t::iterator iter = sets_by_obj.find(b);
120       if (iter == sets_by_obj.end()) {
121          //fprintf(stderr, "%s[%d]:  no annotations for object %p\n", FILE__, __LINE__, b);
122          return NULL;
123       }
124
125       as_id_map_t &anno_sets_by_id = iter->second;
126       typename as_id_map_t::iterator nm_iter = anno_sets_by_id.find(anno_id);
127       if (nm_iter == anno_sets_by_id.end()) {
128          //fprintf(stderr, "%s[%d]:  no annotations of type %d for object %p\n", 
129          //      FILE__, __LINE__, anno_id, b);
130          return NULL;
131       }
132
133       return nm_iter->second;
134    }
135
136    static T *getAnnotationSet(char *b, int anno_id)
137    {
138       T *it = NULL;
139
140       if (NULL == (it = findAnnotationSet(b, anno_id))) {
141          //fprintf(stderr, "%s[%d]:  creating new annotation set for %p id %d\n", FILE__, __LINE__, b,anno_id);
142          //fprintf(stderr, "%s[%d]:  sets_by_obj.size() = %d\n", FILE__, __LINE__, sets_by_obj.size());
143
144          //  operator[] should create new elements if they don't exist
145          as_id_map_t &id_map = sets_by_obj[b];
146
147          //  wee sanity check...
148          if (sets_by_obj.end() == sets_by_obj.find(b)) {
149             fprintf(stderr, "%s[%d]:  FATAL!? &sets_by_obj = %p, b = %p\n", FILE__, __LINE__, &sets_by_obj, b);
150             fprintf(stderr, "%s[%d]:  sets_by_obj.size() = %d\n", FILE__, __LINE__, sets_by_obj.size());
151          }
152
153          // sanity check, make sure this map does not contain <name> already
154          typename as_id_map_t::iterator iter = id_map.find(anno_id);
155          if (iter != id_map.end()) {
156             //  we have already created a container for this annotation type, for this particular
157             //  object, just return it.
158             return iter->second;
159          //   fprintf(stderr, "%s[%d]:  WARNING:  exists:  object %p, id %d, size %d container = %s\n", FILE__, __LINE__, b, anno_id, iter->second->size(),typeid(T).name());
160          }
161
162          it = new T();
163          id_map[anno_id] = it;
164       }
165
166       return it;
167    }
168
169
170    static bool removeAnnotationSet(char *b, int anno_id)
171    {
172       typename obj_map_t::iterator iter = sets_by_obj.find(b);
173       if (iter == sets_by_obj.end())
174          return false;
175
176       as_id_map_t *anno_sets_by_id_ptr  = iter->second;
177       assert(anno_sets_by_id_ptr);
178       as_id_map_t &anno_sets_by_id = *anno_sets_by_id_ptr;
179
180       typename as_id_map_t::iterator nm_iter = anno_sets_by_id.find(anno_id);
181       if (nm_iter == anno_sets_by_id.end()) {
182          // sanity check that this map is not empty
183          assert(anno_sets_by_id.size());
184          return false;
185       }
186
187       delete nm_iter->second;
188       anno_sets_by_id.erase(nm_iter);
189       
190       //  if we just got rid of the last element of the map, get rid of the map
191       //  (within a map) as well.
192       if (!anno_sets_by_id.size()) {
193          fprintf(stderr, "%s[%d]:  DELETING\n", FILE__, __LINE__);
194          delete anno_sets_by_id_ptr;
195          sets_by_obj.erase(iter);
196       }
197
198       return true;
199    }
200 };
201
202 template< class T > hash_map<char *, hash_map<int, T*> >
203 AnnotationSet< T >::sets_by_obj;
204
205 #if 0
206 class AnnotationTypeNameBase {
207    static hash_map<std::string, AnnotationTypeNameBase *> type_name_map;
208    std::string name;
209    public:
210    AnnotationTypeNameBase(std::string name_) :
211       name(name_) 
212    {
213       hash_map<std::string, AnnotationTypeNameBase *>::iterator iter;
214       iter = type_name_map.find(name);
215       if (iter != type_name_map.end()) {
216          fprintf(stderr, "%s[%d]:  WARNING:  already have entry for %s<->%p in map\n",
217                FILE__, __LINE__, name.c_str(), iter->second);
218       }
219       type_name_map[name] = this;
220    }
221 };
222
223 template <class T> 
224 class AnnotationTypeName : public AnnotationTypeNameBase {
225    public:
226       AnnotationTypeName(std::string name) :
227          AnnotationTypeNameBase(name) 
228       {
229       }
230       
231 };
232 #endif
233
234 template <class T, class ANNOTATION_NAME_T, bool SERIALIZABLE = false>
235 class Annotatable : public AnnotatableBase
236 {
237    public:
238       Annotatable() :
239          AnnotatableBase()
240       {
241       }
242       ~Annotatable() 
243       {
244       }
245
246       Annotatable(const Annotatable<T, ANNOTATION_NAME_T, SERIALIZABLE> &/*src*/) :
247          AnnotatableBase()
248       {/*hrm deep copy here or no?*/}
249
250       typedef typename std::vector<T> Container_t;
251       Container_t *initAnnotations()
252       {
253          Container_t *v = NULL;
254          std::string anno_name = typeid(ANNOTATION_NAME_T).name();
255
256          int anno_id = getOrCreateAnnotationType(anno_name);
257          if (anno_id == -1) {
258             fprintf(stderr, "%s[%d]:  failed to getOrCreateAnnotation type %s\n", 
259                   FILE__, __LINE__, anno_name.c_str());
260             return NULL;
261          }
262
263          v = AnnotationSet<Container_t>::getAnnotationSet((char *)this, anno_id);
264          if (v) {
265             //fprintf(stderr, "%s[%d]:  annotation set already exists for %s/%p\n", 
266             //      FILE__, __LINE__, anno_name.c_str(), this);
267             return v;
268          }
269
270          if (!v) {
271             fprintf(stderr, "%s[%d]:  malloc problem\n", FILE__, __LINE__);
272             abort();
273             return NULL;
274          }
275
276          return v;
277       }
278
279       bool addAnnotation(T it)
280       {
281          Container_t *v = NULL;
282          std::string anno_name = typeid(ANNOTATION_NAME_T).name();
283          int anno_id = getOrCreateAnnotationType(anno_name);
284          if (anno_id == -1) {
285             fprintf(stderr, "%s[%d]:  failed to getOrCreateAnnotation type %s\n", 
286                   FILE__, __LINE__, anno_name.c_str());
287             return false;
288          }
289
290          v = AnnotationSet<std::vector<T> >::findAnnotationSet((char *)this, anno_id);
291          if (!v)
292             if (NULL == ( v = initAnnotations())) {
293                fprintf(stderr, "%s[%d]:  bad annotation type\n", FILE__, __LINE__);
294                return false;
295             }
296
297          if (!v) {
298             fprintf (stderr, "%s[%d]:  initAnnotations failed\n", FILE__, __LINE__);
299             return false;
300          }
301
302          v->push_back(it);
303
304 #if defined (cap_serialization)
305          if (SERIALIZABLE) {
306             fprintf(stderr, "%s[%d]:  serializing annotation here for %s\n", FILE__, __LINE__, anno_name.c_str());
307          }
308 #endif
309          return true;
310       }
311
312       void clearAnnotations()
313       {
314          Container_t *v = NULL;
315          std::string anno_name = typeid(ANNOTATION_NAME_T).name();
316          int anno_id = getOrCreateAnnotationType(anno_name);
317          if (anno_id == -1) {
318             return;
319          }
320          v = AnnotationSet<std::vector<T> >::findAnnotationSet((char *)this, anno_id);
321          if (v)
322             v->clear();
323       }
324
325       unsigned size() const {
326          Container_t *v = NULL;
327          std::string anno_name = typeid(ANNOTATION_NAME_T).name();
328          int anno_id = getOrCreateAnnotationType(anno_name);
329          if (anno_id == -1) {
330             fprintf(stderr, "%s[%d]:  failed to getOrCreateAnnotation type %s\n", 
331                   FILE__, __LINE__, anno_name.c_str());
332             return 0;
333          }
334
335          //  ahhh the things we do to get rid of constness
336          const Annotatable<T, ANNOTATION_NAME_T, SERIALIZABLE> *thc = this; 
337          Annotatable<T, ANNOTATION_NAME_T, SERIALIZABLE> *th  
338             = const_cast<Annotatable<T, ANNOTATION_NAME_T, SERIALIZABLE> *> (thc);
339          //fprintf(stderr, "%s[%d]: looking for annotation set for %p/%p\n", FILE__, __LINE__, this, th);
340          v = AnnotationSet<Container_t>::findAnnotationSet((char *)th, anno_id);
341          if (!v) {
342             //fprintf(stderr, "%s[%d]:  no annotation set for id %d\n", FILE__, __LINE__, anno_id);
343             return 0;
344          }
345          return v->size();
346       }
347
348       //  so called getDataStructure in case we generalize beyond vectors for annotations
349       std::vector<T> &getDataStructure() {
350          // use with caution since this function will assert upon failure 
351          // (it has no way to return errors)
352          // when in doubt, check size() first.
353          Container_t *v = NULL;
354          std::string anno_name = typeid(ANNOTATION_NAME_T).name();
355          int anno_id = getOrCreateAnnotationType(anno_name);
356          if (anno_id == -1) {
357             fprintf(stderr, "%s[%d]:  failed to getOrCreateAnnotation type %s\n", 
358                   FILE__, __LINE__, anno_name.c_str());
359             assert(0);
360          }
361          v = AnnotationSet<Container_t>::findAnnotationSet((char *)this, anno_id);
362          if (!v)
363             if (NULL == (v = initAnnotations())) {
364                fprintf(stderr, "%s[%d]:  failed to init annotations here\n", 
365                      FILE__, __LINE__);
366                assert(0);
367             }
368          return *v;
369       }
370
371       T &getAnnotation(unsigned index) const
372       {
373          Container_t *v = NULL;
374          std::string anno_name = typeid(ANNOTATION_NAME_T).name();
375          int anno_id = getOrCreateAnnotationType(anno_name);
376          if (anno_id == -1) {
377             fprintf(stderr, "%s[%d]:  failed to getOrCreateAnnotation type %s\n", 
378                   FILE__, __LINE__, anno_name.c_str());
379             assert(0);
380          }
381
382          //  ahhh the things we do to get rid of constness
383          const Annotatable<T, ANNOTATION_NAME_T, SERIALIZABLE> *thc = this; 
384          Annotatable<T, ANNOTATION_NAME_T, SERIALIZABLE> *th  
385             = const_cast<Annotatable<T, ANNOTATION_NAME_T, SERIALIZABLE> *> (thc);
386
387          v = AnnotationSet<Container_t>::findAnnotationSet((char *)th, anno_id);
388          if (!v) {
389             fprintf(stderr, "%s[%d]:  cannot find annotation set for anno type %s\n", 
390                   FILE__, __LINE__, anno_name.c_str());
391             v = AnnotationSet<Container_t>::getAnnotationSet((char *)th, anno_id);
392          }
393          assert(v);
394          if (index >= v->size()) {
395             fprintf(stderr, "%s[%d]:  FIXME:  index = %d -- size = %d\n", FILE__, __LINE__, index, v->size());
396          }
397          assert(index < v->size());
398          return (*v)[index];
399       }
400
401       T &operator[](unsigned index) const {return getAnnotation(index);}
402
403 };
404
405 template <class S, class T>
406 bool annotate(S *obj, T &anno, std::string anno_name)
407 {
408    assert(obj);
409    //AnnotatableBase *tobj = (AnnotatableBase *) obj;
410    char *tobj = (char *) obj;
411    std::vector<T> *v = NULL;
412
413    int anno_id = AnnotatableBase::getOrCreateAnnotationType(anno_name);
414    if (anno_id == -1) {
415       fprintf(stderr, "%s[%d]:  failed to getOrCreateAnnotation type %s\n", 
416             FILE__, __LINE__, anno_name.c_str());
417       return false;
418    }
419
420    v = AnnotationSet<std::vector<T> >::getAnnotationSet(tobj, anno_id);
421    if (!v) {
422       fprintf(stderr, "%s[%d]:  failed to init annotations here\n", 
423             FILE__, __LINE__);
424       assert(0);
425    }
426
427    v->push_back(anno);
428    return true;
429 }
430
431 template <class S, class T>
432 std::vector<T> *getAnnotations(S *obj, std::string anno_name)
433 {
434    //  does not allocate anything, should return NULL if there are none
435    assert(obj);
436    char *tobj = (char *) obj;
437    std::vector<T> *v = NULL;
438
439    int anno_id = AnnotatableBase::getOrCreateAnnotationType(anno_name);
440    if (anno_id == -1) {
441       fprintf(stderr, "%s[%d]:  failed to getOrCreateAnnotation type %s\n", 
442             FILE__, __LINE__, anno_name.c_str());
443       return false;
444    }
445
446    v = AnnotationSet<std::vector<T> >::findAnnotationSet(tobj, anno_id);
447    return v;
448 }
449 #endif