Files
TheRock/rocm-systems/projects/rocprofiler-systems/external/dyninst/common/h/Annotatable.h
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

749 lines
20 KiB
C++

/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __ANNOTATABLE_H__
#define __ANNOTATABLE_H__
#if defined (MSC_VER)
#define DYN_DETAIL_BOOST_NO_INTRINSIC_WCHAR_T 1
#endif
#include "dyntypes.h"
#include <stddef.h>
#include <vector>
#include <map>
#include <typeinfo>
#include <string>
#include <string.h> // for strrchr()
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "util.h"
#include "compiler_annotations.h"
namespace Dyninst
{
COMMON_EXPORT bool annotation_debug_flag();
COMMON_EXPORT int annotatable_printf(const char *format, ...)
DYNINST_PRINTF_ANNOTATION(1, 2);
typedef unsigned short AnnotationClassID;
typedef bool (*anno_cmp_func_t)(void *, void*);
extern int newAnnotationClass();
extern bool void_ptr_cmp_func(void *, void *);
class COMMON_EXPORT AnnotationClassBase
{
private:
static std::vector<AnnotationClassBase *> *annotation_types;
static dyn_hash_map<std::string, AnnotationClassID> *annotation_ids_by_name;
anno_cmp_func_t cmp_func;
AnnotationClassID id;
std::string name;
protected:
AnnotationClassBase(std::string n,
anno_cmp_func_t cmp_func_ = NULL);
virtual ~AnnotationClassBase();
public:
static AnnotationClassBase *findAnnotationClass(unsigned int id);
static void dumpAnnotationClasses();
AnnotationClassID getID() { return id; }
std::string &getName() {return name;}
anno_cmp_func_t getCmpFunc() {return cmp_func;}
virtual const char *getTypeName() = 0;
virtual void *allocate() = 0;
};
template <class T>
class AnnotationClass : public AnnotationClassBase {
public:
AnnotationClass(std::string n,
anno_cmp_func_t cmp_func_ = NULL) :
AnnotationClassBase(n, cmp_func_)
{
}
const char *getTypeName() { return typeid(T).name();}
void *allocate() DYNINST_MALLOC_ANNOTATION
{
return (void *) new T();
}
size_t size() {return sizeof(T);}
#if 0
bool isSparselyAnnotatable();
bool isDenselyAnnotatable();
#endif
};
typedef enum {
sparse,
dense
} sparse_or_dense_anno_t;
typedef struct {
AnnotationClassBase *acb;
void *data;
void *parent_id;
sparse_or_dense_anno_t sod;
} ser_rec_t;
typedef enum {
sp_add_anno = 2,
sp_rem_anno = 3,
sp_add_cont_item = 4,
sp_rem_cont_item = 5
} ser_post_op_t;
COMMON_EXPORT const char *serPostOp2Str(ser_post_op_t);
class COMMON_EXPORT AnnotatableDense
{
typedef void *anno_list_t;
/**
* Inheriting from this class adds a pointer to each object. Multiple
* types of annotations are stored under this pointer in a
* annotation_type -> anno_list_t map.
**/
private:
typedef anno_list_t anno_map_t;
struct aInfo {
anno_map_t *data;
AnnotationClassID max;
};
aInfo *annotations;
bool addAnnotation(const void *a, AnnotationClassID id)
{
if (annotation_debug_flag())
{
fprintf(stderr, "%s[%d]: Dense(%p) add %s-%d\n", FILE__, __LINE__, (void*)this,
AnnotationClassBase::findAnnotationClass(id)
? AnnotationClassBase::findAnnotationClass(id)->getName().c_str()
: "bad_anno_id", id);
}
unsigned size = id + 1;
if (!annotations)
{
annotations = (aInfo *) malloc(sizeof(aInfo));
annotations->data = NULL;
}
// can have case where we have allocated annotations struct but not the
// actual annotations data array in case where we have performed serialization
if (annotations->data == NULL)
{
annotations->data = (anno_list_t *) calloc(sizeof(anno_list_t), (size));
annotations->max = size;
for (unsigned i=0; i<size; i++)
annotations->data[i] = NULL;
}
else if (id >= annotations->max)
{
int old_max = annotations->max;
size = annotations->max * 2;
annotations->max = size;
annotations->data = (anno_list_t *) realloc(annotations->data, sizeof(anno_list_t) * size);
for (unsigned i=old_max; i<size; i++)
annotations->data[i] = NULL;
}
annotations->data[id] = const_cast<void *>(a);
return true;
}
public:
AnnotatableDense() : annotations(NULL)
{
}
~AnnotatableDense()
{
if (annotations)
{
if (annotations->data)
free(annotations->data);
free(annotations);
}
}
AnnotatableDense(const AnnotatableDense&) = default;
AnnotatableDense& operator=(const AnnotatableDense& rhs)
{
if (this != &rhs)
{
if (annotations)
{
if (annotations->data)
free(annotations->data);
free(annotations);
}
if (rhs.annotations)
{
annotations = (aInfo *) malloc(sizeof(aInfo));
unsigned size = rhs.annotations->max;
annotations->max = size;
annotations->data = (anno_list_t *)calloc(sizeof(anno_list_t), (size));
memcpy(annotations->data, rhs.annotations->data, size * sizeof(anno_list_t));
} else {
annotations = NULL;
}
}
return *this;
}
template<class T>
bool addAnnotation(const T *a, AnnotationClass<T> &a_id)
{
if (annotation_debug_flag())
{
fprintf(stderr, "%s[%d]: Dense(%p): Add %s-%d, %s\n", FILE__, __LINE__,
(void*)this, a_id.getName().c_str(), a_id.getID(), typeid(T).name());
}
int id = a_id.getID();
T *a_noconst = const_cast<T *>(a);
bool ret = addAnnotation((void *)a_noconst, id);
if (!ret)
{
fprintf(stderr, "%s[%d]: failed to add annotation\n", FILE__, __LINE__);
return ret;
}
return true;
}
template<class T>
inline bool getAnnotation(T *&a, AnnotationClass<T> &a_id) const
{
if (!annotations)
return false;
int id = a_id.getID();
if (id > annotations->max)
{
return false;
}
a = (T *) annotations->data[id];
if (!a) return false;
return true;
}
template<class T>
inline bool removeAnnotation(AnnotationClass<T> &a_id)
{
if (annotation_debug_flag())
{
fprintf(stderr, "%s[%d]: Dense(%p) remove %s-%d, %s\n", FILE__, __LINE__,
(void*)this, a_id.getName().c_str(), a_id.getID(), a_id.getTypeName());
}
if (!annotations) return false;
int id = a_id.getID();
if (id > annotations->max)
{
return false;
}
if (!annotations->data[id])
return false;
annotations->data[id] = NULL;
return true;
}
void annotationsReport()
{
std::vector<AnnotationClassBase *> atypes;
if (annotations && annotations->data)
{
for (unsigned int i = 0; i < annotations->max; ++i)
{
if (NULL != annotations->data[i])
{
AnnotationClassBase *acb = AnnotationClassBase::findAnnotationClass(i);
if (!acb)
{
fprintf(stderr, "%s[%d]: ERROR: failed to find acb for %u\n",
FILE__, __LINE__, i);
continue;
}
else
atypes.push_back(acb);
}
}
fprintf(stderr, "%s[%d]: Dense(%p): have %lu annotations\n",
FILE__, __LINE__, (void*)this, (unsigned long) atypes.size());
for (unsigned int i = 0; i < atypes.size(); ++i)
{
fprintf(stderr, "\t%s-%d, %s\n", atypes[i]->getName().c_str(),
atypes[i]->getID(), atypes[i]->getTypeName());
}
}
}
};
#define NON_STATIC_SPARSE_MAP 1
#define AN_INLINE inline
class COMMON_EXPORT AnnotatableSparse
{
public:
struct void_ptr_hasher
{
size_t operator()(const void* a) const noexcept
{
return (size_t) a;
}
};
#if defined (_MSC_VER)
typedef dyn_hash_map<void *, void *> annos_by_type_t;
#else
typedef dyn_hash_map<void *, void *, void_ptr_hasher> annos_by_type_t;
#endif
typedef std::vector<annos_by_type_t *> annos_t;
AnnotatableSparse() = default;
~AnnotatableSparse()
{
ClearAnnotations("dtor");
}
AnnotatableSparse(const AnnotatableSparse&) = default;
AnnotatableSparse& operator=(const AnnotatableSparse &rhs)
{
if (this != &rhs)
{
ClearAnnotations("operator=");
}
return *this;
}
private:
void ClearAnnotations(const char *reason)
{
// We need to remove annotations from the static map when objects
// are destroyed: (1) memory may be reclaimed and reused at the same
// place, and (2) regardless of 1, the map can possibly explode to
// unmanageable sizes, with a lot of unused junk in it if a lot of i
// annotatable objects are created and destroyed.
// Alas this is kinda expensive right now, but the data structure is
// set up to minimize search time, not deletion time. It could
// be changed if this becomes a significant time drain.
for (unsigned int i = 0; i < getAnnos()->size(); ++i)
{
annos_by_type_t *abt = (*getAnnos())[i];
if (!abt) continue;
annos_by_type_t::iterator iter = abt->find(this);
if (iter != abt->end())
{
if (annotation_debug_flag())
{
fprintf(stderr, "%s[%d]: Sparse(%p) %s remove %s-%u\n", FILE__, __LINE__,
(void*)this, reason, AnnotationClassBase::findAnnotationClass(i)
? AnnotationClassBase::findAnnotationClass(i)->getName().c_str()
: "bad_anno_id", i);
}
abt->erase(iter);
// get rid of this check... just making sure that erase is behaving as
// expected...
annos_by_type_t::iterator iter2 = abt->find(this);
if (iter2 != abt->end())
fprintf(stderr, "%s[%d]: FIXME: REMOVE FAILED\n", FILE__, __LINE__);
}
}
}
#if defined (NON_STATIC_SPARSE_MAP)
//COMMON_EXPORT static annos_t *annos;
#else
static annos_t annos;
#endif
annos_t *getAnnos() const;
static dyn_hash_map<void *, unsigned short> ser_ndx_map;
annos_by_type_t *getAnnosOfType(AnnotationClassID aid, bool do_create =false) const
{
annos_t &l_annos = *getAnnos();
long nelems_to_create = aid - l_annos.size() + 1;
if (nelems_to_create > 0)
{
if (!do_create)
{
return NULL;
}
while (nelems_to_create)
{
annos_by_type_t *newl = new annos_by_type_t();
l_annos.push_back(newl);
nelems_to_create--;
}
}
annos_by_type_t *abt = l_annos[aid];
return abt;
}
template <class T>
AN_INLINE annos_by_type_t *getAnnosOfType(AnnotationClass<T> &a_id, bool do_create =false) const
{
AnnotationClassID aid = a_id.getID();
return getAnnosOfType(aid, do_create);
}
void *getAnnosForObject(annos_by_type_t *abt,
void *obj, bool do_create = false) const
{
assert(abt);
assert(obj);
void *target = NULL;
annos_by_type_t::iterator iter = abt->find(obj);
if (iter == abt->end())
{
if (!do_create)
{
return NULL;
}
(*abt)[obj] = target;
}
else
{
target = iter->second;
}
return target;
}
AN_INLINE bool addAnnotation(const void *a, AnnotationClassID aid)
{
if (annotation_debug_flag())
{
fprintf(stderr, "%s[%d]: Sparse(%p) add %s-%d void\n", FILE__, __LINE__, (void*)this,
AnnotationClassBase::findAnnotationClass(aid)
? AnnotationClassBase::findAnnotationClass(aid)->getName().c_str()
: "bad_anno_id", aid);
}
void *obj = this;
annos_by_type_t *abt = getAnnosOfType(aid, true /*do create if needed*/);
assert(abt);
annos_by_type_t::iterator iter = abt->find(obj);
if (iter == abt->end())
{
(*abt)[obj] = const_cast<void *>(a);
}
else
{
// do silent replacement -- this case can arise if an annotatable object
// is destroyed and then reallocated as a new object at the same address.
// Given the sparse map data structure, it would be rather expensive to
// go through the map in the dtor to eliminate references to the
// destroyed object.
// Added annotation removal in dtor... so this case should _not_ arise,
// do the replacement, but make some noise:
if (a != iter->second)
{
annotatable_printf("%s[%d]: WEIRD: already have annotation of this type: %p, replacing with %p\n", FILE__, __LINE__, (void*)iter->second, (const void*)a);
iter->second = const_cast<void *>(a);
}
return true;
}
return true;
}
public:
bool operator==(AnnotatableSparse &cmp)
{
annos_t &l_annos = *getAnnos();
unsigned this_ntypes = l_annos.size();
unsigned cmp_ntypes = cmp.getAnnos()->size();
unsigned ntypes = (cmp_ntypes > this_ntypes) ? cmp_ntypes : this_ntypes;
for (unsigned int i = 0; i < ntypes; ++i)
{
if ((i >= cmp_ntypes) || (i >= this_ntypes))
{
// compare is done since at least one set of annotations
// has been exhausted
break;
}
annos_by_type_t *this_abt = l_annos[i];
annos_by_type_t *cmp_abt = (*cmp.getAnnos())[i];
if (!this_abt)
{
fprintf(stderr, "%s[%d]: WEIRD: FIXME\n", FILE__, __LINE__);
continue;
}
if (!cmp_abt)
{
fprintf(stderr, "%s[%d]: WEIRD: FIXME\n", FILE__, __LINE__);
continue;
}
annos_by_type_t::iterator this_abt_iter = this_abt->find(this);
annos_by_type_t::iterator cmp_abt_iter = cmp_abt->find(&cmp);
// if one has annotations of this particular type and other other
// doesn't, then we are def. not equal, so fail:
if (this_abt_iter == this_abt->end())
{
if (cmp_abt_iter != cmp_abt->end())
{
return false;
}
// both are at end()
continue;
}
if ( (cmp_abt_iter == cmp_abt->end())
&& (this_abt_iter != this_abt->end()))
{
return false;
}
AnnotationClassBase *acb = AnnotationClassBase::findAnnotationClass(i);
if (!acb)
{
return false;
}
// both have annotation -- do the compare
anno_cmp_func_t cmpfunc = acb->getCmpFunc();
if (!cmpfunc)
{
// even if not explicitly specified, a default pointer-compare
// function should be returned here.
fprintf(stderr, "%s[%d]: no cmp func for anno id %u\n",
FILE__, __LINE__, i);
return false;
}
void *arg1 = cmp_abt_iter->second;
void *arg2 = this_abt_iter->second;
bool ret = (*cmpfunc)(arg1, arg2);
return ret;
}
return true;
}
template<class T>
AN_INLINE bool addAnnotation(const T *a, AnnotationClass<T> &a_id)
{
annotatable_printf("%s[%d]: Sparse(%p): Add %s-%d, %s\n", FILE__, __LINE__,
(void*)this, a_id.getName().c_str(), a_id.getID(), typeid(T).name());
void *obj = this;
annos_by_type_t *abt = getAnnosOfType(a_id, true /*do create if needed*/);
assert(abt);
annos_by_type_t::iterator iter = abt->find(obj);
if (iter == abt->end())
{
(*abt)[obj] = (void *) const_cast<T *>(a);
}
else
{
// do silent replacement -- this case can arise if an annotatable object
// is destroyed and then reallocated as a new object at the same address.
// Given the sparse map data structure, it would be rather expensive to
// go through the map in the dtor to eliminate references to the
// destroyed object.
// Added annotation removal in dtor... so this case should _not_ arise,
// do the replacement, but make some noise:
if (iter->second != a)
{
//fprintf(stderr, "%s[%d]: WEIRD: already have annotation of type %s: %p, replacing with %p\n", FILE__, __LINE__, a_id.getName().c_str(), iter->second, a);
iter->second = (void *)const_cast<T *>(a);
}
return true;
}
return true;
}
template<class T>
AN_INLINE bool getAnnotation(T *&a, AnnotationClass<T> &a_id) const
{
a = NULL;
annos_by_type_t *abt = getAnnosOfType(a_id, false /*don't create if none*/);
if (!abt)
{
return false;
}
AnnotatableSparse * this_noconst = const_cast<AnnotatableSparse *>(this);
void *annos_for_object = getAnnosForObject(abt, (void *)this_noconst,
false /*no create if none*/);
if (!annos_for_object)
{
return false;
}
a = (T *)annos_for_object;
return true;
}
template<class T>
inline bool removeAnnotation(AnnotationClass<T> &a_id)
{
if (annotation_debug_flag())
{
fprintf(stderr, "%s[%d]: Sparse(%p) remove %s-%d, %s\n", FILE__, __LINE__,
(void*)this, a_id.getName().c_str(), a_id.getID(), typeid(T).name());
}
void *obj = this;
annos_by_type_t *abt = getAnnosOfType(a_id, false /*do create if needed*/);
assert(abt);
annos_by_type_t::iterator iter = abt->find(obj);
if (iter == abt->end())
{
// annotation does not exist, so we return false (remove failed)
return false;
}
else
{
abt->erase(iter);
return true;
}
return false;
}
void annotationsReport()
{
std::vector<AnnotationClassBase *> atypes;
annos_t &l_annos = *getAnnos();
for (AnnotationClassID id = 0; id < l_annos.size(); ++id)
{
annos_by_type_t *abt = getAnnosOfType(id, false /*don't do create */);
if (NULL == abt) continue;
annos_by_type_t::iterator iter = abt->find(this);
if (iter == abt->end())
{
// fprintf(stderr, "%s[%d]: nothing for this obj\n", FILE__, __LINE__);
continue;
}
AnnotationClassBase *acb = AnnotationClassBase::findAnnotationClass(id);
if (!acb)
{
fprintf(stderr, "%s[%d]: FIXME, cant find anno class base for id %d\n",
FILE__, __LINE__, id);
continue;
}
atypes.push_back(acb);
}
fprintf(stderr, "%s[%d]: Sparse(%p): have %lu annos:\n", FILE__, __LINE__,
(void*)this, (unsigned long) atypes.size());
for (unsigned int i = 0; i < atypes.size(); ++i)
{
fprintf(stderr, "\t%s-%d, %s\n", atypes[i]->getName().c_str(),
atypes[i]->getID(), atypes[i]->getTypeName());
}
}
};
} // namespace
#endif