]> Zhao Yanbai Git Server - minix.git/commitdiff
Import magic library from llvm-apps 43/3143/1
authorDavid van Moolenbroek <david@minix3.org>
Tue, 30 Jun 2015 16:19:11 +0000 (18:19 +0200)
committerDavid van Moolenbroek <david@minix3.org>
Thu, 17 Sep 2015 13:58:32 +0000 (13:58 +0000)
Change-Id: Icfbcfae6afc731a23e71448a7a5d0045b2c219e5

41 files changed:
minix/llvm/include/common/ut/uthash.h [new file with mode: 0644]
minix/llvm/include/common/ut/utlist.h [new file with mode: 0644]
minix/llvm/include/magic.h [new file with mode: 0644]
minix/llvm/include/magic_analysis.h [new file with mode: 0644]
minix/llvm/include/magic_asr.h [new file with mode: 0644]
minix/llvm/include/magic_def.h [new file with mode: 0644]
minix/llvm/include/magic_eval.h [new file with mode: 0644]
minix/llvm/include/magic_eval_lib.h [new file with mode: 0644]
minix/llvm/include/magic_mem.h [new file with mode: 0644]
minix/llvm/include/magic_range.h [new file with mode: 0644]
minix/llvm/include/magic_rcu.h [new file with mode: 0644]
minix/llvm/include/magic_real_mem.h [new file with mode: 0644]
minix/llvm/include/magic_selement.h [new file with mode: 0644]
minix/llvm/include/magic_sentry.h [new file with mode: 0644]
minix/llvm/include/magic_splay_tree.h [new file with mode: 0644]
minix/llvm/include/magic_structs.h [new file with mode: 0644]
minix/llvm/include/st/callback.h [new file with mode: 0644]
minix/llvm/include/st/cb_template.h [new file with mode: 0644]
minix/llvm/include/st/metadata_transfer.h [new file with mode: 0644]
minix/llvm/include/st/os_callback.h [new file with mode: 0644]
minix/llvm/include/st/private.h [new file with mode: 0644]
minix/llvm/include/st/special.h [new file with mode: 0644]
minix/llvm/include/st/state_transfer.h [new file with mode: 0644]
minix/llvm/include/st/typedefs.h [new file with mode: 0644]
minix/llvm/static/Makefile.settings [new file with mode: 0644]
minix/llvm/static/magic/Makefile [new file with mode: 0644]
minix/llvm/static/magic/Makefile.inc [new file with mode: 0644]
minix/llvm/static/magic/Makefile.magic_st [new file with mode: 0644]
minix/llvm/static/magic/magic.c [new file with mode: 0644]
minix/llvm/static/magic/magic_analysis.c [new file with mode: 0644]
minix/llvm/static/magic/magic_asr.c [new file with mode: 0644]
minix/llvm/static/magic/magic_eval.c [new file with mode: 0644]
minix/llvm/static/magic/magic_eval_lib.c [new file with mode: 0644]
minix/llvm/static/magic/magic_mem.c [new file with mode: 0644]
minix/llvm/static/magic/magic_range.c [new file with mode: 0644]
minix/llvm/static/magic/magic_selement.c [new file with mode: 0644]
minix/llvm/static/magic/magic_sentry.c [new file with mode: 0644]
minix/llvm/static/magic/magic_splay_tree.c [new file with mode: 0644]
minix/llvm/static/magic/magic_st.c [new file with mode: 0644]
minix/llvm/static/magic/minix/magic_ds.c [new file with mode: 0644]
minix/llvm/static/magic/minix/magic_util.c [new file with mode: 0644]

diff --git a/minix/llvm/include/common/ut/uthash.h b/minix/llvm/include/common/ut/uthash.h
new file mode 100644 (file)
index 0000000..909cb0a
--- /dev/null
@@ -0,0 +1,940 @@
+/*
+Copyright (c) 2003-2013, Troy D. Hanson     http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTHASH_H
+#define UTHASH_H 
+
+#include <string.h>   /* memcmp,strlen */
+#include <stddef.h>   /* ptrdiff_t */
+#include <stdlib.h>   /* exit() */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+   As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+   when compiling c++ source) this code uses whatever method is needed
+   or, for VS2008 where neither is available, uses casting workarounds. */
+#ifdef _MSC_VER         /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else                   /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#endif
+#else                   /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE_ASSIGN(dst,src)                                                 \
+do {                                                                             \
+  char **_da_dst = (char**)(&(dst));                                             \
+  *_da_dst = (char*)(src);                                                       \
+} while(0)
+#else 
+#define DECLTYPE_ASSIGN(dst,src)                                                 \
+do {                                                                             \
+  (dst) = DECLTYPE(dst)(src);                                                    \
+} while(0)
+#endif
+
+/* a number of the hash function use uint32_t which isn't defined on win32 */
+#ifdef _MSC_VER
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#else
+#include <inttypes.h>   /* uint32_t */
+#endif
+
+#define UTHASH_VERSION 1.9.8
+
+#ifndef uthash_fatal
+#define uthash_fatal(msg) exit(-1)        /* fatal error (out of memory,etc) */
+#endif
+#ifndef uthash_malloc
+#define uthash_malloc(sz) malloc(sz)      /* malloc fcn                      */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr,sz) free(ptr)     /* free fcn                        */
+#endif
+
+#ifndef uthash_noexpand_fyi
+#define uthash_noexpand_fyi(tbl)          /* can be defined to log noexpand  */
+#endif
+#ifndef uthash_expand_fyi
+#define uthash_expand_fyi(tbl)            /* can be defined to log expands   */
+#endif
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32      /* initial number of buckets        */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5  /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10      /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhe */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+
+#define HASH_FIND(hh,head,keyptr,keylen,out)                                     \
+do {                                                                             \
+  unsigned _hf_bkt,_hf_hashv;                                                    \
+  out=NULL;                                                                      \
+  if (head) {                                                                    \
+     HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt);   \
+     if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) {                           \
+       HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ],  \
+                        keyptr,keylen,out);                                      \
+     }                                                                           \
+  }                                                                              \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
+#define HASH_BLOOM_MAKE(tbl)                                                     \
+do {                                                                             \
+  (tbl)->bloom_nbits = HASH_BLOOM;                                               \
+  (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN);                 \
+  if (!((tbl)->bloom_bv))  { uthash_fatal( "out of memory"); }                   \
+  memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN);                                \
+  (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE;                                       \
+} while (0) 
+
+#define HASH_BLOOM_FREE(tbl)                                                     \
+do {                                                                             \
+  uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN);                              \
+} while (0) 
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
+
+#define HASH_BLOOM_ADD(tbl,hashv)                                                \
+  HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#define HASH_BLOOM_TEST(tbl,hashv)                                               \
+  HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl) 
+#define HASH_BLOOM_FREE(tbl) 
+#define HASH_BLOOM_ADD(tbl,hashv) 
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#define HASH_BLOOM_BYTELEN 0
+#endif
+
+#define HASH_MAKE_TABLE(hh,head)                                                 \
+do {                                                                             \
+  (head)->hh.tbl = (UT_hash_table*)uthash_malloc(                                \
+                  sizeof(UT_hash_table));                                        \
+  if (!((head)->hh.tbl))  { uthash_fatal( "out of memory"); }                    \
+  memset((head)->hh.tbl, 0, sizeof(UT_hash_table));                              \
+  (head)->hh.tbl->tail = &((head)->hh);                                          \
+  (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS;                        \
+  (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2;              \
+  (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head);                    \
+  (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc(                      \
+          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+  if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); }             \
+  memset((head)->hh.tbl->buckets, 0,                                             \
+          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+  HASH_BLOOM_MAKE((head)->hh.tbl);                                               \
+  (head)->hh.tbl->signature = HASH_SIGNATURE;                                    \
+} while(0)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
+        HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add)
+
+#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced)                   \
+do {                                                                             \
+  replaced=NULL;                                                                 \
+  HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced);                     \
+  if (replaced!=NULL) {                                                          \
+     HASH_DELETE(hh,head,replaced);                                              \
+  };                                                                             \
+  HASH_ADD(hh,head,fieldname,keylen_in,add);                                     \
+} while(0)
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
+do {                                                                             \
+ unsigned _ha_bkt;                                                               \
+ (add)->hh.next = NULL;                                                          \
+ (add)->hh.key = (char*)keyptr;                                                  \
+ (add)->hh.keylen = (unsigned)keylen_in;                                                   \
+ if (!(head)) {                                                                  \
+    head = (add);                                                                \
+    (head)->hh.prev = NULL;                                                      \
+    HASH_MAKE_TABLE(hh,head);                                                    \
+ } else {                                                                        \
+    (head)->hh.tbl->tail->next = (add);                                          \
+    (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail);         \
+    (head)->hh.tbl->tail = &((add)->hh);                                         \
+ }                                                                               \
+ (head)->hh.tbl->num_items++;                                                    \
+ (add)->hh.tbl = (head)->hh.tbl;                                                 \
+ HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets,                         \
+         (add)->hh.hashv, _ha_bkt);                                              \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh);                   \
+ HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv);                                 \
+ HASH_EMIT_KEY(hh,head,keyptr,keylen_in);                                        \
+ HASH_FSCK(hh,head);                                                             \
+} while(0)
+
+#define HASH_TO_BKT( hashv, num_bkts, bkt )                                      \
+do {                                                                             \
+  bkt = ((hashv) & ((num_bkts) - 1));                                            \
+} while(0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ *  HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr)                                              \
+do {                                                                             \
+    unsigned _hd_bkt;                                                            \
+    struct UT_hash_handle *_hd_hh_del;                                           \
+    if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) )  {         \
+        uthash_free((head)->hh.tbl->buckets,                                     \
+                    (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+        HASH_BLOOM_FREE((head)->hh.tbl);                                         \
+        uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                      \
+        head = NULL;                                                             \
+    } else {                                                                     \
+        _hd_hh_del = &((delptr)->hh);                                            \
+        if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) {     \
+            (head)->hh.tbl->tail =                                               \
+                (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) +               \
+                (head)->hh.tbl->hho);                                            \
+        }                                                                        \
+        if ((delptr)->hh.prev) {                                                 \
+            ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) +                  \
+                    (head)->hh.tbl->hho))->next = (delptr)->hh.next;             \
+        } else {                                                                 \
+            DECLTYPE_ASSIGN(head,(delptr)->hh.next);                             \
+        }                                                                        \
+        if (_hd_hh_del->next) {                                                  \
+            ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next +                     \
+                    (head)->hh.tbl->hho))->prev =                                \
+                    _hd_hh_del->prev;                                            \
+        }                                                                        \
+        HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt);   \
+        HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del);        \
+        (head)->hh.tbl->num_items--;                                             \
+    }                                                                            \
+    HASH_FSCK(hh,head);                                                          \
+} while (0)
+
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out)                                          \
+    HASH_FIND(hh,head,findstr,strlen(findstr),out)
+#define HASH_ADD_STR(head,strfield,add)                                          \
+    HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
+#define HASH_REPLACE_STR(head,strfield,add,replaced)                             \
+  HASH_REPLACE(hh,head,strfield,strlen(add->strfield),add,replaced)
+#define HASH_FIND_INT(head,findint,out)                                          \
+    HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add)                                          \
+    HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_REPLACE_INT(head,intfield,add,replaced)                             \
+    HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
+#define HASH_FIND_PTR(head,findptr,out)                                          \
+    HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add)                                          \
+    HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_REPLACE_PTR(head,ptrfield,add)                                      \
+    HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
+#define HASH_DEL(head,delptr)                                                    \
+    HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+ */
+#ifdef HASH_DEBUG
+#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+#define HASH_FSCK(hh,head)                                                       \
+do {                                                                             \
+    unsigned _bkt_i;                                                             \
+    unsigned _count, _bkt_count;                                                 \
+    char *_prev;                                                                 \
+    struct UT_hash_handle *_thh;                                                 \
+    if (head) {                                                                  \
+        _count = 0;                                                              \
+        for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) {       \
+            _bkt_count = 0;                                                      \
+            _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head;                      \
+            _prev = NULL;                                                        \
+            while (_thh) {                                                       \
+               if (_prev != (char*)(_thh->hh_prev)) {                            \
+                   HASH_OOPS("invalid hh_prev %p, actual %p\n",                  \
+                    _thh->hh_prev, _prev );                                      \
+               }                                                                 \
+               _bkt_count++;                                                     \
+               _prev = (char*)(_thh);                                            \
+               _thh = _thh->hh_next;                                             \
+            }                                                                    \
+            _count += _bkt_count;                                                \
+            if ((head)->hh.tbl->buckets[_bkt_i].count !=  _bkt_count) {          \
+               HASH_OOPS("invalid bucket count %d, actual %d\n",                 \
+                (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count);              \
+            }                                                                    \
+        }                                                                        \
+        if (_count != (head)->hh.tbl->num_items) {                               \
+            HASH_OOPS("invalid hh item count %d, actual %d\n",                   \
+                (head)->hh.tbl->num_items, _count );                             \
+        }                                                                        \
+        /* traverse hh in app order; check next/prev integrity, count */         \
+        _count = 0;                                                              \
+        _prev = NULL;                                                            \
+        _thh =  &(head)->hh;                                                     \
+        while (_thh) {                                                           \
+           _count++;                                                             \
+           if (_prev !=(char*)(_thh->prev)) {                                    \
+              HASH_OOPS("invalid prev %p, actual %p\n",                          \
+                    _thh->prev, _prev );                                         \
+           }                                                                     \
+           _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh);                    \
+           _thh = ( _thh->next ?  (UT_hash_handle*)((char*)(_thh->next) +        \
+                                  (head)->hh.tbl->hho) : NULL );                 \
+        }                                                                        \
+        if (_count != (head)->hh.tbl->num_items) {                               \
+            HASH_OOPS("invalid app item count %d, actual %d\n",                  \
+                (head)->hh.tbl->num_items, _count );                             \
+        }                                                                        \
+    }                                                                            \
+} while (0)
+#else
+#define HASH_FSCK(hh,head) 
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to 
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include <unistd.h> to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)                                   \
+do {                                                                             \
+    unsigned _klen = fieldlen;                                                   \
+    write(HASH_EMIT_KEYS, &_klen, sizeof(_klen));                                \
+    write(HASH_EMIT_KEYS, keyptr, fieldlen);                                     \
+} while (0)
+#else 
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)                    
+#endif
+
+/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+#ifdef HASH_FUNCTION 
+#define HASH_FCN HASH_FUNCTION
+#else
+#define HASH_FCN HASH_JEN
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6 */
+#define HASH_BER(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _hb_keylen=keylen;                                                    \
+  char *_hb_key=(char*)(key);                                                    \
+  (hashv) = 0;                                                                   \
+  while (_hb_keylen--)  { (hashv) = ((hashv) * 33) + *_hb_key++; }               \
+  bkt = (hashv) & (num_bkts-1);                                                  \
+} while (0)
+
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at 
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
+#define HASH_SAX(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _sx_i;                                                                \
+  char *_hs_key=(char*)(key);                                                    \
+  hashv = 0;                                                                     \
+  for(_sx_i=0; _sx_i < keylen; _sx_i++)                                          \
+      hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i];                     \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while (0)
+
+#define HASH_FNV(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _fn_i;                                                                \
+  char *_hf_key=(char*)(key);                                                    \
+  hashv = 2166136261UL;                                                          \
+  for(_fn_i=0; _fn_i < keylen; _fn_i++)                                          \
+      hashv = (hashv * 16777619) ^ _hf_key[_fn_i];                               \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0) 
+#define HASH_OAT(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _ho_i;                                                                \
+  char *_ho_key=(char*)(key);                                                    \
+  hashv = 0;                                                                     \
+  for(_ho_i=0; _ho_i < keylen; _ho_i++) {                                        \
+      hashv += _ho_key[_ho_i];                                                   \
+      hashv += (hashv << 10);                                                    \
+      hashv ^= (hashv >> 6);                                                     \
+  }                                                                              \
+  hashv += (hashv << 3);                                                         \
+  hashv ^= (hashv >> 11);                                                        \
+  hashv += (hashv << 15);                                                        \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0)
+
+#define HASH_JEN_MIX(a,b,c)                                                      \
+do {                                                                             \
+  a -= b; a -= c; a ^= ( c >> 13 );                                              \
+  b -= c; b -= a; b ^= ( a << 8 );                                               \
+  c -= a; c -= b; c ^= ( b >> 13 );                                              \
+  a -= b; a -= c; a ^= ( c >> 12 );                                              \
+  b -= c; b -= a; b ^= ( a << 16 );                                              \
+  c -= a; c -= b; c ^= ( b >> 5 );                                               \
+  a -= b; a -= c; a ^= ( c >> 3 );                                               \
+  b -= c; b -= a; b ^= ( a << 10 );                                              \
+  c -= a; c -= b; c ^= ( b >> 15 );                                              \
+} while (0)
+
+#define HASH_JEN(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _hj_i,_hj_j,_hj_k;                                                    \
+  unsigned char *_hj_key=(unsigned char*)(key);                                  \
+  hashv = 0xfeedbeef;                                                            \
+  _hj_i = _hj_j = 0x9e3779b9;                                                    \
+  _hj_k = (unsigned)keylen;                                                      \
+  while (_hj_k >= 12) {                                                          \
+    _hj_i +=    (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 )                      \
+        + ( (unsigned)_hj_key[2] << 16 )                                         \
+        + ( (unsigned)_hj_key[3] << 24 ) );                                      \
+    _hj_j +=    (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 )                      \
+        + ( (unsigned)_hj_key[6] << 16 )                                         \
+        + ( (unsigned)_hj_key[7] << 24 ) );                                      \
+    hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 )                         \
+        + ( (unsigned)_hj_key[10] << 16 )                                        \
+        + ( (unsigned)_hj_key[11] << 24 ) );                                     \
+                                                                                 \
+     HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                          \
+                                                                                 \
+     _hj_key += 12;                                                              \
+     _hj_k -= 12;                                                                \
+  }                                                                              \
+  hashv += keylen;                                                               \
+  switch ( _hj_k ) {                                                             \
+     case 11: hashv += ( (unsigned)_hj_key[10] << 24 );                          \
+     case 10: hashv += ( (unsigned)_hj_key[9] << 16 );                           \
+     case 9:  hashv += ( (unsigned)_hj_key[8] << 8 );                            \
+     case 8:  _hj_j += ( (unsigned)_hj_key[7] << 24 );                           \
+     case 7:  _hj_j += ( (unsigned)_hj_key[6] << 16 );                           \
+     case 6:  _hj_j += ( (unsigned)_hj_key[5] << 8 );                            \
+     case 5:  _hj_j += _hj_key[4];                                               \
+     case 4:  _hj_i += ( (unsigned)_hj_key[3] << 24 );                           \
+     case 3:  _hj_i += ( (unsigned)_hj_key[2] << 16 );                           \
+     case 2:  _hj_i += ( (unsigned)_hj_key[1] << 8 );                            \
+     case 1:  _hj_i += _hj_key[0];                                               \
+  }                                                                              \
+  HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                             \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)             \
+  || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)             \
+                       +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned char *_sfh_key=(unsigned char*)(key);                                 \
+  uint32_t _sfh_tmp, _sfh_len = keylen;                                          \
+                                                                                 \
+  int _sfh_rem = _sfh_len & 3;                                                   \
+  _sfh_len >>= 2;                                                                \
+  hashv = 0xcafebabe;                                                            \
+                                                                                 \
+  /* Main loop */                                                                \
+  for (;_sfh_len > 0; _sfh_len--) {                                              \
+    hashv    += get16bits (_sfh_key);                                            \
+    _sfh_tmp       = (uint32_t)(get16bits (_sfh_key+2)) << 11  ^ hashv;          \
+    hashv     = (hashv << 16) ^ _sfh_tmp;                                        \
+    _sfh_key += 2*sizeof (uint16_t);                                             \
+    hashv    += hashv >> 11;                                                     \
+  }                                                                              \
+                                                                                 \
+  /* Handle end cases */                                                         \
+  switch (_sfh_rem) {                                                            \
+    case 3: hashv += get16bits (_sfh_key);                                       \
+            hashv ^= hashv << 16;                                                \
+            hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18);              \
+            hashv += hashv >> 11;                                                \
+            break;                                                               \
+    case 2: hashv += get16bits (_sfh_key);                                       \
+            hashv ^= hashv << 11;                                                \
+            hashv += hashv >> 17;                                                \
+            break;                                                               \
+    case 1: hashv += *_sfh_key;                                                  \
+            hashv ^= hashv << 10;                                                \
+            hashv += hashv >> 1;                                                 \
+  }                                                                              \
+                                                                                 \
+    /* Force "avalanching" of final 127 bits */                                  \
+    hashv ^= hashv << 3;                                                         \
+    hashv += hashv >> 5;                                                         \
+    hashv ^= hashv << 4;                                                         \
+    hashv += hashv >> 17;                                                        \
+    hashv ^= hashv << 25;                                                        \
+    hashv += hashv >> 6;                                                         \
+    bkt = hashv & (num_bkts-1);                                                  \
+} while(0) 
+
+#ifdef HASH_USING_NO_STRICT_ALIASING
+/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
+ * MurmurHash uses the faster approach only on CPU's where we know it's safe. 
+ *
+ * Note the preprocessor built-in defines can be emitted using:
+ *
+ *   gcc -m64 -dM -E - < /dev/null                  (on gcc)
+ *   cc -## a.c (where a.c is a simple test file)   (Sun Studio)
+ */
+#if (defined(__i386__) || defined(__x86_64__)  || defined(_M_IX86))
+#define MUR_GETBLOCK(p,i) p[i]
+#else /* non intel */
+#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0)
+#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1)
+#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2)
+#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3)
+#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
+#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
+#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
+#define MUR_TWO_TWO(p)   ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >>  8))
+#else /* assume little endian non-intel */
+#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
+#define MUR_TWO_TWO(p)   ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) <<  8))
+#endif
+#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) :           \
+                            (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
+                             (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) :  \
+                                                      MUR_ONE_THREE(p))))
+#endif
+#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
+#define MUR_FMIX(_h) \
+do {                 \
+  _h ^= _h >> 16;    \
+  _h *= 0x85ebca6b;  \
+  _h ^= _h >> 13;    \
+  _h *= 0xc2b2ae35l; \
+  _h ^= _h >> 16;    \
+} while(0)
+
+#define HASH_MUR(key,keylen,num_bkts,hashv,bkt)                        \
+do {                                                                   \
+  const uint8_t *_mur_data = (const uint8_t*)(key);                    \
+  const int _mur_nblocks = (keylen) / 4;                               \
+  uint32_t _mur_h1 = 0xf88D5353;                                       \
+  uint32_t _mur_c1 = 0xcc9e2d51;                                       \
+  uint32_t _mur_c2 = 0x1b873593;                                       \
+  uint32_t _mur_k1 = 0;                                                \
+  const uint8_t *_mur_tail;                                            \
+  const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \
+  int _mur_i;                                                          \
+  for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) {                      \
+    _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i);                        \
+    _mur_k1 *= _mur_c1;                                                \
+    _mur_k1 = MUR_ROTL32(_mur_k1,15);                                  \
+    _mur_k1 *= _mur_c2;                                                \
+                                                                       \
+    _mur_h1 ^= _mur_k1;                                                \
+    _mur_h1 = MUR_ROTL32(_mur_h1,13);                                  \
+    _mur_h1 = _mur_h1*5+0xe6546b64;                                    \
+  }                                                                    \
+  _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4);            \
+  _mur_k1=0;                                                           \
+  switch((keylen) & 3) {                                               \
+    case 3: _mur_k1 ^= _mur_tail[2] << 16;                             \
+    case 2: _mur_k1 ^= _mur_tail[1] << 8;                              \
+    case 1: _mur_k1 ^= _mur_tail[0];                                   \
+    _mur_k1 *= _mur_c1;                                                \
+    _mur_k1 = MUR_ROTL32(_mur_k1,15);                                  \
+    _mur_k1 *= _mur_c2;                                                \
+    _mur_h1 ^= _mur_k1;                                                \
+  }                                                                    \
+  _mur_h1 ^= (keylen);                                                 \
+  MUR_FMIX(_mur_h1);                                                   \
+  hashv = _mur_h1;                                                     \
+  bkt = hashv & (num_bkts-1);                                          \
+} while(0)
+#endif  /* HASH_USING_NO_STRICT_ALIASING */
+
+/* key comparison function; return 0 if keys equal */
+#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) 
+
+/* iterate over items in a known bucket to find desired item */
+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out)                       \
+do {                                                                             \
+ if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head));          \
+ else out=NULL;                                                                  \
+ while (out) {                                                                   \
+    if ((out)->hh.keylen == keylen_in) {                                           \
+        if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break;             \
+    }                                                                            \
+    if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \
+    else out = NULL;                                                             \
+ }                                                                               \
+} while(0)
+
+/* add an item to a bucket  */
+#define HASH_ADD_TO_BKT(head,addhh)                                              \
+do {                                                                             \
+ head.count++;                                                                   \
+ (addhh)->hh_next = head.hh_head;                                                \
+ (addhh)->hh_prev = NULL;                                                        \
+ if (head.hh_head) { (head).hh_head->hh_prev = (addhh); }                        \
+ (head).hh_head=addhh;                                                           \
+ if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH)             \
+     && (addhh)->tbl->noexpand != 1) {                                           \
+       HASH_EXPAND_BUCKETS((addhh)->tbl);                                        \
+ }                                                                               \
+} while(0)
+
+/* remove an item from a given bucket */
+#define HASH_DEL_IN_BKT(hh,head,hh_del)                                          \
+    (head).count--;                                                              \
+    if ((head).hh_head == hh_del) {                                              \
+      (head).hh_head = hh_del->hh_next;                                          \
+    }                                                                            \
+    if (hh_del->hh_prev) {                                                       \
+        hh_del->hh_prev->hh_next = hh_del->hh_next;                              \
+    }                                                                            \
+    if (hh_del->hh_next) {                                                       \
+        hh_del->hh_next->hh_prev = hh_del->hh_prev;                              \
+    }                                                                
+
+/* Bucket expansion has the effect of doubling the number of buckets
+ * and redistributing the items into the new buckets. Ideally the
+ * items will distribute more or less evenly into the new buckets
+ * (the extent to which this is true is a measure of the quality of
+ * the hash function as it applies to the key domain). 
+ * 
+ * With the items distributed into more buckets, the chain length
+ * (item count) in each bucket is reduced. Thus by expanding buckets
+ * the hash keeps a bound on the chain length. This bounded chain 
+ * length is the essence of how a hash provides constant time lookup.
+ * 
+ * The calculation of tbl->ideal_chain_maxlen below deserves some
+ * explanation. First, keep in mind that we're calculating the ideal
+ * maximum chain length based on the *new* (doubled) bucket count.
+ * In fractions this is just n/b (n=number of items,b=new num buckets).
+ * Since the ideal chain length is an integer, we want to calculate 
+ * ceil(n/b). We don't depend on floating point arithmetic in this
+ * hash, so to calculate ceil(n/b) with integers we could write
+ * 
+ *      ceil(n/b) = (n/b) + ((n%b)?1:0)
+ * 
+ * and in fact a previous version of this hash did just that.
+ * But now we have improved things a bit by recognizing that b is
+ * always a power of two. We keep its base 2 log handy (call it lb),
+ * so now we can write this with a bit shift and logical AND:
+ * 
+ *      ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+ * 
+ */
+#define HASH_EXPAND_BUCKETS(tbl)                                                 \
+do {                                                                             \
+    unsigned _he_bkt;                                                            \
+    unsigned _he_bkt_i;                                                          \
+    struct UT_hash_handle *_he_thh, *_he_hh_nxt;                                 \
+    UT_hash_bucket *_he_new_buckets, *_he_newbkt;                                \
+    _he_new_buckets = (UT_hash_bucket*)uthash_malloc(                            \
+             2 * tbl->num_buckets * sizeof(struct UT_hash_bucket));              \
+    if (!_he_new_buckets) { uthash_fatal( "out of memory"); }                    \
+    memset(_he_new_buckets, 0,                                                   \
+            2 * tbl->num_buckets * sizeof(struct UT_hash_bucket));               \
+    tbl->ideal_chain_maxlen =                                                    \
+       (tbl->num_items >> (tbl->log2_num_buckets+1)) +                           \
+       ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0);                    \
+    tbl->nonideal_items = 0;                                                     \
+    for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++)                \
+    {                                                                            \
+        _he_thh = tbl->buckets[ _he_bkt_i ].hh_head;                             \
+        while (_he_thh) {                                                        \
+           _he_hh_nxt = _he_thh->hh_next;                                        \
+           HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt);            \
+           _he_newbkt = &(_he_new_buckets[ _he_bkt ]);                           \
+           if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) {                \
+             tbl->nonideal_items++;                                              \
+             _he_newbkt->expand_mult = _he_newbkt->count /                       \
+                                        tbl->ideal_chain_maxlen;                 \
+           }                                                                     \
+           _he_thh->hh_prev = NULL;                                              \
+           _he_thh->hh_next = _he_newbkt->hh_head;                               \
+           if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev =               \
+                _he_thh;                                                         \
+           _he_newbkt->hh_head = _he_thh;                                        \
+           _he_thh = _he_hh_nxt;                                                 \
+        }                                                                        \
+    }                                                                            \
+    uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+    tbl->num_buckets *= 2;                                                       \
+    tbl->log2_num_buckets++;                                                     \
+    tbl->buckets = _he_new_buckets;                                              \
+    tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ?         \
+        (tbl->ineff_expands+1) : 0;                                              \
+    if (tbl->ineff_expands > 1) {                                                \
+        tbl->noexpand=1;                                                         \
+        uthash_noexpand_fyi(tbl);                                                \
+    }                                                                            \
+    uthash_expand_fyi(tbl);                                                      \
+} while(0)
+
+
+/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+/* Note that HASH_SORT assumes the hash handle name to be hh. 
+ * HASH_SRT was added to allow the hash handle name to be passed in. */
+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+#define HASH_SRT(hh,head,cmpfcn)                                                 \
+do {                                                                             \
+  unsigned _hs_i;                                                                \
+  unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize;               \
+  struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail;            \
+  if (head) {                                                                    \
+      _hs_insize = 1;                                                            \
+      _hs_looping = 1;                                                           \
+      _hs_list = &((head)->hh);                                                  \
+      while (_hs_looping) {                                                      \
+          _hs_p = _hs_list;                                                      \
+          _hs_list = NULL;                                                       \
+          _hs_tail = NULL;                                                       \
+          _hs_nmerges = 0;                                                       \
+          while (_hs_p) {                                                        \
+              _hs_nmerges++;                                                     \
+              _hs_q = _hs_p;                                                     \
+              _hs_psize = 0;                                                     \
+              for ( _hs_i = 0; _hs_i  < _hs_insize; _hs_i++ ) {                  \
+                  _hs_psize++;                                                   \
+                  _hs_q = (UT_hash_handle*)((_hs_q->next) ?                      \
+                          ((void*)((char*)(_hs_q->next) +                        \
+                          (head)->hh.tbl->hho)) : NULL);                         \
+                  if (! (_hs_q) ) break;                                         \
+              }                                                                  \
+              _hs_qsize = _hs_insize;                                            \
+              while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) {           \
+                  if (_hs_psize == 0) {                                          \
+                      _hs_e = _hs_q;                                             \
+                      _hs_q = (UT_hash_handle*)((_hs_q->next) ?                  \
+                              ((void*)((char*)(_hs_q->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_qsize--;                                               \
+                  } else if ( (_hs_qsize == 0) || !(_hs_q) ) {                   \
+                      _hs_e = _hs_p;                                             \
+                      _hs_p = (UT_hash_handle*)((_hs_p->next) ?                  \
+                              ((void*)((char*)(_hs_p->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_psize--;                                               \
+                  } else if ((                                                   \
+                      cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
+                             DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
+                             ) <= 0) {                                           \
+                      _hs_e = _hs_p;                                             \
+                      _hs_p = (UT_hash_handle*)((_hs_p->next) ?                  \
+                              ((void*)((char*)(_hs_p->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_psize--;                                               \
+                  } else {                                                       \
+                      _hs_e = _hs_q;                                             \
+                      _hs_q = (UT_hash_handle*)((_hs_q->next) ?                  \
+                              ((void*)((char*)(_hs_q->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_qsize--;                                               \
+                  }                                                              \
+                  if ( _hs_tail ) {                                              \
+                      _hs_tail->next = ((_hs_e) ?                                \
+                            ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL);          \
+                  } else {                                                       \
+                      _hs_list = _hs_e;                                          \
+                  }                                                              \
+                  _hs_e->prev = ((_hs_tail) ?                                    \
+                     ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL);              \
+                  _hs_tail = _hs_e;                                              \
+              }                                                                  \
+              _hs_p = _hs_q;                                                     \
+          }                                                                      \
+          _hs_tail->next = NULL;                                                 \
+          if ( _hs_nmerges <= 1 ) {                                              \
+              _hs_looping=0;                                                     \
+              (head)->hh.tbl->tail = _hs_tail;                                   \
+              DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list));      \
+          }                                                                      \
+          _hs_insize *= 2;                                                       \
+      }                                                                          \
+      HASH_FSCK(hh,head);                                                        \
+ }                                                                               \
+} while (0)
+
+/* This function selects items from one hash into another hash. 
+ * The end result is that the selected items have dual presence 
+ * in both hashes. There is no copy of the items made; rather 
+ * they are added into the new hash through a secondary hash 
+ * hash handle that must be present in the structure. */
+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond)                              \
+do {                                                                             \
+  unsigned _src_bkt, _dst_bkt;                                                   \
+  void *_last_elt=NULL, *_elt;                                                   \
+  UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL;                         \
+  ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst));                 \
+  if (src) {                                                                     \
+    for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) {     \
+      for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head;                \
+          _src_hh;                                                               \
+          _src_hh = _src_hh->hh_next) {                                          \
+          _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh);                       \
+          if (cond(_elt)) {                                                      \
+            _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho);               \
+            _dst_hh->key = _src_hh->key;                                         \
+            _dst_hh->keylen = _src_hh->keylen;                                   \
+            _dst_hh->hashv = _src_hh->hashv;                                     \
+            _dst_hh->prev = _last_elt;                                           \
+            _dst_hh->next = NULL;                                                \
+            if (_last_elt_hh) { _last_elt_hh->next = _elt; }                     \
+            if (!dst) {                                                          \
+              DECLTYPE_ASSIGN(dst,_elt);                                         \
+              HASH_MAKE_TABLE(hh_dst,dst);                                       \
+            } else {                                                             \
+              _dst_hh->tbl = (dst)->hh_dst.tbl;                                  \
+            }                                                                    \
+            HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt);    \
+            HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh);            \
+            (dst)->hh_dst.tbl->num_items++;                                      \
+            _last_elt = _elt;                                                    \
+            _last_elt_hh = _dst_hh;                                              \
+          }                                                                      \
+      }                                                                          \
+    }                                                                            \
+  }                                                                              \
+  HASH_FSCK(hh_dst,dst);                                                         \
+} while (0)
+
+#define HASH_CLEAR(hh,head)                                                      \
+do {                                                                             \
+  if (head) {                                                                    \
+    uthash_free((head)->hh.tbl->buckets,                                         \
+                (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket));      \
+    HASH_BLOOM_FREE((head)->hh.tbl);                                             \
+    uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                          \
+    (head)=NULL;                                                                 \
+  }                                                                              \
+} while(0)
+
+#define HASH_OVERHEAD(hh,head)                                                   \
+ (size_t)((((head)->hh.tbl->num_items   * sizeof(UT_hash_handle))   +            \
+           ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket))   +            \
+            (sizeof(UT_hash_table))                                 +            \
+            (HASH_BLOOM_BYTELEN)))
+
+#ifdef NO_DECLTYPE
+#define HASH_ITER(hh,head,el,tmp)                                                \
+for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL);       \
+  el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) 
+#else
+#define HASH_ITER(hh,head,el,tmp)                                                \
+for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL);                 \
+  el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
+#endif
+
+/* obtain a count of items in the hash */
+#define HASH_COUNT(head) HASH_CNT(hh,head) 
+#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
+
+typedef struct UT_hash_bucket {
+   struct UT_hash_handle *hh_head;
+   unsigned count;
+
+   /* expand_mult is normally set to 0. In this situation, the max chain length
+    * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+    * the bucket's chain exceeds this length, bucket expansion is triggered). 
+    * However, setting expand_mult to a non-zero value delays bucket expansion
+    * (that would be triggered by additions to this particular bucket)
+    * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+    * (The multiplier is simply expand_mult+1). The whole idea of this
+    * multiplier is to reduce bucket expansions, since they are expensive, in
+    * situations where we know that a particular bucket tends to be overused.
+    * It is better to let its chain length grow to a longer yet-still-bounded
+    * value, than to do an O(n) bucket expansion too often. 
+    */
+   unsigned expand_mult;
+
+} UT_hash_bucket;
+
+/* random signature used only to find hash tables in external analysis */
+#define HASH_SIGNATURE 0xa0111fe1
+#define HASH_BLOOM_SIGNATURE 0xb12220f2
+
+typedef struct UT_hash_table {
+   UT_hash_bucket *buckets;
+   unsigned num_buckets, log2_num_buckets;
+   unsigned num_items;
+   struct UT_hash_handle *tail; /* tail hh in app order, for fast append    */
+   ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
+
+   /* in an ideal situation (all buckets used equally), no bucket would have
+    * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+   unsigned ideal_chain_maxlen;
+
+   /* nonideal_items is the number of items in the hash whose chain position
+    * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+    * hash distribution; reaching them in a chain traversal takes >ideal steps */
+   unsigned nonideal_items;
+
+   /* ineffective expands occur when a bucket doubling was performed, but 
+    * afterward, more than half the items in the hash had nonideal chain
+    * positions. If this happens on two consecutive expansions we inhibit any
+    * further expansion, as it's not helping; this happens when the hash
+    * function isn't a good fit for the key domain. When expansion is inhibited
+    * the hash will still work, albeit no longer in constant time. */
+   unsigned ineff_expands, noexpand;
+
+   uint32_t signature; /* used only to find hash tables in external analysis */
+#ifdef HASH_BLOOM
+   uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
+   uint8_t *bloom_bv;
+   char bloom_nbits;
+#endif
+
+} UT_hash_table;
+
+typedef struct UT_hash_handle {
+   struct UT_hash_table *tbl;
+   void *prev;                       /* prev element in app order      */
+   void *next;                       /* next element in app order      */
+   struct UT_hash_handle *hh_prev;   /* previous hh in bucket order    */
+   struct UT_hash_handle *hh_next;   /* next hh in bucket order        */
+   void *key;                        /* ptr to enclosing struct's key  */
+   unsigned keylen;                  /* enclosing struct's key len     */
+   unsigned hashv;                   /* result of hash-fcn(key)        */
+} UT_hash_handle;
+
+#endif /* UTHASH_H */
diff --git a/minix/llvm/include/common/ut/utlist.h b/minix/llvm/include/common/ut/utlist.h
new file mode 100644 (file)
index 0000000..6bccec7
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+Copyright (c) 2007-2013, Troy D. Hanson   http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTLIST_H
+#define UTLIST_H
+
+#define UTLIST_VERSION 1.9.8
+
+#include <assert.h>
+
+/* 
+ * This file contains macros to manipulate singly and doubly-linked lists.
+ *
+ * 1. LL_ macros:  singly-linked lists.
+ * 2. DL_ macros:  doubly-linked lists.
+ * 3. CDL_ macros: circular doubly-linked lists.
+ *
+ * To use singly-linked lists, your structure must have a "next" pointer.
+ * To use doubly-linked lists, your structure must "prev" and "next" pointers.
+ * Either way, the pointer to the head of the list must be initialized to NULL.
+ * 
+ * ----------------.EXAMPLE -------------------------
+ * struct item {
+ *      int id;
+ *      struct item *prev, *next;
+ * }
+ *
+ * struct item *list = NULL:
+ *
+ * int main() {
+ *      struct item *item;
+ *      ... allocate and populate item ...
+ *      DL_APPEND(list, item);
+ * }
+ * --------------------------------------------------
+ *
+ * For doubly-linked lists, the append and delete macros are O(1)
+ * For singly-linked lists, append and delete are O(n) but prepend is O(1)
+ * The sort macro is O(n log(n)) for all types of single/double/circular lists.
+ */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+   As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+   when compiling c++ code), this code uses whatever method is needed
+   or, for VS2008 where neither is available, uses casting workarounds. */
+#ifdef _MSC_VER            /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */
+#define LDECLTYPE(x) decltype(x)
+#else                     /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define LDECLTYPE(x) char*
+#endif
+#else                      /* GNU, Sun and other compilers */
+#define LDECLTYPE(x) __typeof(x)
+#endif
+
+/* for VS2008 we use some workarounds to get around the lack of decltype,
+ * namely, we always reassign our tmp variable to the list head if we need
+ * to dereference its prev/next pointers, and save/restore the real head.*/
+#ifdef NO_DECLTYPE
+#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
+#define _NEXT(elt,list,next) ((char*)((list)->next))
+#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
+/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */
+#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
+#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
+#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
+#else 
+#define _SV(elt,list)
+#define _NEXT(elt,list,next) ((elt)->next)
+#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to)
+/* #define _PREV(elt,list,prev) ((elt)->prev) */
+#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to)
+#define _RS(list)
+#define _CASTASGN(a,b) (a)=(b)
+#endif
+
+/******************************************************************************
+ * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort    *
+ * Unwieldy variable names used here to avoid shadowing passed-in variables.  *
+ *****************************************************************************/
+#define LL_SORT(list, cmp)                                                                     \
+    LL_SORT2(list, cmp, next)
+
+#define LL_SORT2(list, cmp, next)                                                              \
+do {                                                                                           \
+  LDECLTYPE(list) _ls_p;                                                                       \
+  LDECLTYPE(list) _ls_q;                                                                       \
+  LDECLTYPE(list) _ls_e;                                                                       \
+  LDECLTYPE(list) _ls_tail;                                                                    \
+  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+  if (list) {                                                                                  \
+    _ls_insize = 1;                                                                            \
+    _ls_looping = 1;                                                                           \
+    while (_ls_looping) {                                                                      \
+      _CASTASGN(_ls_p,list);                                                                   \
+      list = NULL;                                                                             \
+      _ls_tail = NULL;                                                                         \
+      _ls_nmerges = 0;                                                                         \
+      while (_ls_p) {                                                                          \
+        _ls_nmerges++;                                                                         \
+        _ls_q = _ls_p;                                                                         \
+        _ls_psize = 0;                                                                         \
+        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+          _ls_psize++;                                                                         \
+          _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list);                          \
+          if (!_ls_q) break;                                                                   \
+        }                                                                                      \
+        _ls_qsize = _ls_insize;                                                                \
+        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+          if (_ls_psize == 0) {                                                                \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+          } else {                                                                             \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+          }                                                                                    \
+          if (_ls_tail) {                                                                      \
+            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
+          } else {                                                                             \
+            _CASTASGN(list,_ls_e);                                                             \
+          }                                                                                    \
+          _ls_tail = _ls_e;                                                                    \
+        }                                                                                      \
+        _ls_p = _ls_q;                                                                         \
+      }                                                                                        \
+      if (_ls_tail) {                                                                          \
+        _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list);                     \
+      }                                                                                        \
+      if (_ls_nmerges <= 1) {                                                                  \
+        _ls_looping=0;                                                                         \
+      }                                                                                        \
+      _ls_insize *= 2;                                                                         \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+
+
+#define DL_SORT(list, cmp)                                                                     \
+    DL_SORT2(list, cmp, prev, next)
+
+#define DL_SORT2(list, cmp, prev, next)                                                        \
+do {                                                                                           \
+  LDECLTYPE(list) _ls_p;                                                                       \
+  LDECLTYPE(list) _ls_q;                                                                       \
+  LDECLTYPE(list) _ls_e;                                                                       \
+  LDECLTYPE(list) _ls_tail;                                                                    \
+  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+  if (list) {                                                                                  \
+    _ls_insize = 1;                                                                            \
+    _ls_looping = 1;                                                                           \
+    while (_ls_looping) {                                                                      \
+      _CASTASGN(_ls_p,list);                                                                   \
+      list = NULL;                                                                             \
+      _ls_tail = NULL;                                                                         \
+      _ls_nmerges = 0;                                                                         \
+      while (_ls_p) {                                                                          \
+        _ls_nmerges++;                                                                         \
+        _ls_q = _ls_p;                                                                         \
+        _ls_psize = 0;                                                                         \
+        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+          _ls_psize++;                                                                         \
+          _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list);                          \
+          if (!_ls_q) break;                                                                   \
+        }                                                                                      \
+        _ls_qsize = _ls_insize;                                                                \
+        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+          if (_ls_psize == 0) {                                                                \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+          } else {                                                                             \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+          }                                                                                    \
+          if (_ls_tail) {                                                                      \
+            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
+          } else {                                                                             \
+            _CASTASGN(list,_ls_e);                                                             \
+          }                                                                                    \
+          _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list);                     \
+          _ls_tail = _ls_e;                                                                    \
+        }                                                                                      \
+        _ls_p = _ls_q;                                                                         \
+      }                                                                                        \
+      _CASTASGN(list->prev, _ls_tail);                                                         \
+      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list);                       \
+      if (_ls_nmerges <= 1) {                                                                  \
+        _ls_looping=0;                                                                         \
+      }                                                                                        \
+      _ls_insize *= 2;                                                                         \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+
+#define CDL_SORT(list, cmp)                                                                    \
+    CDL_SORT2(list, cmp, prev, next)
+
+#define CDL_SORT2(list, cmp, prev, next)                                                       \
+do {                                                                                           \
+  LDECLTYPE(list) _ls_p;                                                                       \
+  LDECLTYPE(list) _ls_q;                                                                       \
+  LDECLTYPE(list) _ls_e;                                                                       \
+  LDECLTYPE(list) _ls_tail;                                                                    \
+  LDECLTYPE(list) _ls_oldhead;                                                                 \
+  LDECLTYPE(list) _tmp;                                                                        \
+  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+  if (list) {                                                                                  \
+    _ls_insize = 1;                                                                            \
+    _ls_looping = 1;                                                                           \
+    while (_ls_looping) {                                                                      \
+      _CASTASGN(_ls_p,list);                                                                   \
+      _CASTASGN(_ls_oldhead,list);                                                             \
+      list = NULL;                                                                             \
+      _ls_tail = NULL;                                                                         \
+      _ls_nmerges = 0;                                                                         \
+      while (_ls_p) {                                                                          \
+        _ls_nmerges++;                                                                         \
+        _ls_q = _ls_p;                                                                         \
+        _ls_psize = 0;                                                                         \
+        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+          _ls_psize++;                                                                         \
+          _SV(_ls_q,list);                                                                     \
+          if (_NEXT(_ls_q,list,next) == _ls_oldhead) {                                         \
+            _ls_q = NULL;                                                                      \
+          } else {                                                                             \
+            _ls_q = _NEXT(_ls_q,list,next);                                                    \
+          }                                                                                    \
+          _RS(list);                                                                           \
+          if (!_ls_q) break;                                                                   \
+        }                                                                                      \
+        _ls_qsize = _ls_insize;                                                                \
+        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+          if (_ls_psize == 0) {                                                                \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+            if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \
+          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+            if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \
+          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+            if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \
+          } else {                                                                             \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+            if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \
+          }                                                                                    \
+          if (_ls_tail) {                                                                      \
+            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
+          } else {                                                                             \
+            _CASTASGN(list,_ls_e);                                                             \
+          }                                                                                    \
+          _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list);                     \
+          _ls_tail = _ls_e;                                                                    \
+        }                                                                                      \
+        _ls_p = _ls_q;                                                                         \
+      }                                                                                        \
+      _CASTASGN(list->prev,_ls_tail);                                                          \
+      _CASTASGN(_tmp,list);                                                                    \
+      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list);                       \
+      if (_ls_nmerges <= 1) {                                                                  \
+        _ls_looping=0;                                                                         \
+      }                                                                                        \
+      _ls_insize *= 2;                                                                         \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+
+/******************************************************************************
+ * singly linked list macros (non-circular)                                   *
+ *****************************************************************************/
+#define LL_PREPEND(head,add)                                                                   \
+    LL_PREPEND2(head,add,next)
+
+#define LL_PREPEND2(head,add,next)                                                             \
+do {                                                                                           \
+  (add)->next = head;                                                                          \
+  head = add;                                                                                  \
+} while (0)
+
+#define LL_CONCAT(head1,head2)                                                                 \
+    LL_CONCAT2(head1,head2,next)
+
+#define LL_CONCAT2(head1,head2,next)                                                           \
+do {                                                                                           \
+  LDECLTYPE(head1) _tmp;                                                                       \
+  if (head1) {                                                                                 \
+    _tmp = head1;                                                                              \
+    while (_tmp->next) { _tmp = _tmp->next; }                                                  \
+    _tmp->next=(head2);                                                                        \
+  } else {                                                                                     \
+    (head1)=(head2);                                                                           \
+  }                                                                                            \
+} while (0)
+
+#define LL_APPEND(head,add)                                                                    \
+    LL_APPEND2(head,add,next)
+
+#define LL_APPEND2(head,add,next)                                                              \
+do {                                                                                           \
+  LDECLTYPE(head) _tmp;                                                                        \
+  (add)->next=NULL;                                                                            \
+  if (head) {                                                                                  \
+    _tmp = head;                                                                               \
+    while (_tmp->next) { _tmp = _tmp->next; }                                                  \
+    _tmp->next=(add);                                                                          \
+  } else {                                                                                     \
+    (head)=(add);                                                                              \
+  }                                                                                            \
+} while (0)
+
+#define LL_DELETE(head,del)                                                                    \
+    LL_DELETE2(head,del,next)
+
+#define LL_DELETE2(head,del,next)                                                              \
+do {                                                                                           \
+  LDECLTYPE(head) _tmp;                                                                        \
+  if ((head) == (del)) {                                                                       \
+    (head)=(head)->next;                                                                       \
+  } else {                                                                                     \
+    _tmp = head;                                                                               \
+    while (_tmp->next && (_tmp->next != (del))) {                                              \
+      _tmp = _tmp->next;                                                                       \
+    }                                                                                          \
+    if (_tmp->next) {                                                                          \
+      _tmp->next = ((del)->next);                                                              \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+
+/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */
+#define LL_APPEND_VS2008(head,add)                                                             \
+    LL_APPEND2_VS2008(head,add,next)
+
+#define LL_APPEND2_VS2008(head,add,next)                                                       \
+do {                                                                                           \
+  if (head) {                                                                                  \
+    (add)->next = head;     /* use add->next as a temp variable */                             \
+    while ((add)->next->next) { (add)->next = (add)->next->next; }                             \
+    (add)->next->next=(add);                                                                   \
+  } else {                                                                                     \
+    (head)=(add);                                                                              \
+  }                                                                                            \
+  (add)->next=NULL;                                                                            \
+} while (0)
+
+#define LL_DELETE_VS2008(head,del)                                                             \
+    LL_DELETE2_VS2008(head,del,next)
+
+#define LL_DELETE2_VS2008(head,del,next)                                                       \
+do {                                                                                           \
+  if ((head) == (del)) {                                                                       \
+    (head)=(head)->next;                                                                       \
+  } else {                                                                                     \
+    char *_tmp = (char*)(head);                                                                \
+    while ((head)->next && ((head)->next != (del))) {                                          \
+      head = (head)->next;                                                                     \
+    }                                                                                          \
+    if ((head)->next) {                                                                        \
+      (head)->next = ((del)->next);                                                            \
+    }                                                                                          \
+    {                                                                                          \
+      char **_head_alias = (char**)&(head);                                                    \
+      *_head_alias = _tmp;                                                                     \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+#ifdef NO_DECLTYPE
+#undef LL_APPEND
+#define LL_APPEND LL_APPEND_VS2008
+#undef LL_DELETE
+#define LL_DELETE LL_DELETE_VS2008
+#undef LL_DELETE2
+#define LL_DELETE2_VS2008
+#undef LL_APPEND2
+#define LL_APPEND2 LL_APPEND2_VS2008
+#undef LL_CONCAT /* no LL_CONCAT_VS2008 */
+#undef DL_CONCAT /* no DL_CONCAT_VS2008 */
+#endif
+/* end VS2008 replacements */
+
+#define LL_FOREACH(head,el)                                                                    \
+    LL_FOREACH2(head,el,next)
+
+#define LL_FOREACH2(head,el,next)                                                              \
+    for(el=head;el;el=(el)->next)
+
+#define LL_FOREACH_SAFE(head,el,tmp)                                                           \
+    LL_FOREACH_SAFE2(head,el,tmp,next)
+
+#define LL_FOREACH_SAFE2(head,el,tmp,next)                                                     \
+  for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
+
+#define LL_SEARCH_SCALAR(head,out,field,val)                                                   \
+    LL_SEARCH_SCALAR2(head,out,field,val,next)
+
+#define LL_SEARCH_SCALAR2(head,out,field,val,next)                                             \
+do {                                                                                           \
+    LL_FOREACH2(head,out,next) {                                                               \
+      if ((out)->field == (val)) break;                                                        \
+    }                                                                                          \
+} while(0) 
+
+#define LL_SEARCH(head,out,elt,cmp)                                                            \
+    LL_SEARCH2(head,out,elt,cmp,next)
+
+#define LL_SEARCH2(head,out,elt,cmp,next)                                                      \
+do {                                                                                           \
+    LL_FOREACH2(head,out,next) {                                                               \
+      if ((cmp(out,elt))==0) break;                                                            \
+    }                                                                                          \
+} while(0) 
+
+#define LL_REPLACE_ELEM(head, el, add)                                                         \
+do {                                                                                           \
+ LDECLTYPE(head) _tmp;                                                                         \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ (add)->next = (el)->next;                                                                     \
+ if ((head) == (el)) {                                                                         \
+  (head) = (add);                                                                              \
+ } else {                                                                                      \
+  _tmp = head;                                                                                 \
+  while (_tmp->next && (_tmp->next != (el))) {                                                 \
+   _tmp = _tmp->next;                                                                          \
+  }                                                                                            \
+  if (_tmp->next) {                                                                            \
+    _tmp->next = (add);                                                                        \
+  }                                                                                            \
+ }                                                                                             \
+} while (0)
+
+#define LL_PREPEND_ELEM(head, el, add)                                                         \
+do {                                                                                           \
+ LDECLTYPE(head) _tmp;                                                                         \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ (add)->next = (el);                                                                           \
+ if ((head) == (el)) {                                                                         \
+  (head) = (add);                                                                              \
+ } else {                                                                                      \
+  _tmp = head;                                                                                 \
+  while (_tmp->next && (_tmp->next != (el))) {                                                 \
+   _tmp = _tmp->next;                                                                          \
+  }                                                                                            \
+  if (_tmp->next) {                                                                            \
+    _tmp->next = (add);                                                                        \
+  }                                                                                            \
+ }                                                                                             \
+} while (0)                                                                                    \
+
+
+/******************************************************************************
+ * doubly linked list macros (non-circular)                                   *
+ *****************************************************************************/
+#define DL_PREPEND(head,add)                                                                   \
+    DL_PREPEND2(head,add,prev,next)
+
+#define DL_PREPEND2(head,add,prev,next)                                                        \
+do {                                                                                           \
+ (add)->next = head;                                                                           \
+ if (head) {                                                                                   \
+   (add)->prev = (head)->prev;                                                                 \
+   (head)->prev = (add);                                                                       \
+ } else {                                                                                      \
+   (add)->prev = (add);                                                                        \
+ }                                                                                             \
+ (head) = (add);                                                                               \
+} while (0)
+
+#define DL_APPEND(head,add)                                                                    \
+    DL_APPEND2(head,add,prev,next)
+
+#define DL_APPEND2(head,add,prev,next)                                                         \
+do {                                                                                           \
+  if (head) {                                                                                  \
+      (add)->prev = (head)->prev;                                                              \
+      (head)->prev->next = (add);                                                              \
+      (head)->prev = (add);                                                                    \
+      (add)->next = NULL;                                                                      \
+  } else {                                                                                     \
+      (head)=(add);                                                                            \
+      (head)->prev = (head);                                                                   \
+      (head)->next = NULL;                                                                     \
+  }                                                                                            \
+} while (0) 
+
+#define DL_CONCAT(head1,head2)                                                                 \
+    DL_CONCAT2(head1,head2,prev,next)
+
+#define DL_CONCAT2(head1,head2,prev,next)                                                      \
+do {                                                                                           \
+  LDECLTYPE(head1) _tmp;                                                                       \
+  if (head2) {                                                                                 \
+    if (head1) {                                                                               \
+        _tmp = (head2)->prev;                                                                  \
+        (head2)->prev = (head1)->prev;                                                         \
+        (head1)->prev->next = (head2);                                                         \
+        (head1)->prev = _tmp;                                                                  \
+    } else {                                                                                   \
+        (head1)=(head2);                                                                       \
+    }                                                                                          \
+  }                                                                                            \
+} while (0) 
+
+#define DL_DELETE(head,del)                                                                    \
+    DL_DELETE2(head,del,prev,next)
+
+#define DL_DELETE2(head,del,prev,next)                                                         \
+do {                                                                                           \
+  assert((del)->prev != NULL);                                                                 \
+  if ((del)->prev == (del)) {                                                                  \
+      (head)=NULL;                                                                             \
+  } else if ((del)==(head)) {                                                                  \
+      (del)->next->prev = (del)->prev;                                                         \
+      (head) = (del)->next;                                                                    \
+  } else {                                                                                     \
+      (del)->prev->next = (del)->next;                                                         \
+      if ((del)->next) {                                                                       \
+          (del)->next->prev = (del)->prev;                                                     \
+      } else {                                                                                 \
+          (head)->prev = (del)->prev;                                                          \
+      }                                                                                        \
+  }                                                                                            \
+} while (0) 
+
+
+#define DL_FOREACH(head,el)                                                                    \
+    DL_FOREACH2(head,el,next)
+
+#define DL_FOREACH2(head,el,next)                                                              \
+    for(el=head;el;el=(el)->next)
+
+/* this version is safe for deleting the elements during iteration */
+#define DL_FOREACH_SAFE(head,el,tmp)                                                           \
+    DL_FOREACH_SAFE2(head,el,tmp,next)
+
+#define DL_FOREACH_SAFE2(head,el,tmp,next)                                                     \
+  for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
+
+/* these are identical to their singly-linked list counterparts */
+#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
+#define DL_SEARCH LL_SEARCH
+#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2
+#define DL_SEARCH2 LL_SEARCH2
+
+#define DL_REPLACE_ELEM(head, el, add)                                                         \
+do {                                                                                           \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ if ((head) == (el)) {                                                                         \
+  (head) = (add);                                                                              \
+  (add)->next = (el)->next;                                                                    \
+  if ((el)->next == NULL) {                                                                    \
+   (add)->prev = (add);                                                                        \
+  } else {                                                                                     \
+   (add)->prev = (el)->prev;                                                                   \
+   (add)->next->prev = (add);                                                                  \
+  }                                                                                            \
+ } else {                                                                                      \
+  (add)->next = (el)->next;                                                                    \
+  (add)->prev = (el)->prev;                                                                    \
+  (add)->prev->next = (add);                                                                   \
+  if ((el)->next == NULL) {                                                                    \
+   (head)->prev = (add);                                                                       \
+  } else {                                                                                     \
+   (add)->next->prev = (add);                                                                  \
+  }                                                                                            \
+ }                                                                                             \
+} while (0)
+
+#define DL_PREPEND_ELEM(head, el, add)                                                         \
+do {                                                                                           \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ (add)->next = (el);                                                                           \
+ (add)->prev = (el)->prev;                                                                     \
+ (el)->prev = (add);                                                                           \
+ if ((head) == (el)) {                                                                         \
+  (head) = (add);                                                                              \
+ } else {                                                                                      \
+  (add)->prev->next = (add);                                                                   \
+ }                                                                                             \
+} while (0)                                                                                    \
+
+
+/******************************************************************************
+ * circular doubly linked list macros                                         *
+ *****************************************************************************/
+#define CDL_PREPEND(head,add)                                                                  \
+    CDL_PREPEND2(head,add,prev,next)
+
+#define CDL_PREPEND2(head,add,prev,next)                                                       \
+do {                                                                                           \
+ if (head) {                                                                                   \
+   (add)->prev = (head)->prev;                                                                 \
+   (add)->next = (head);                                                                       \
+   (head)->prev = (add);                                                                       \
+   (add)->prev->next = (add);                                                                  \
+ } else {                                                                                      \
+   (add)->prev = (add);                                                                        \
+   (add)->next = (add);                                                                        \
+ }                                                                                             \
+(head)=(add);                                                                                  \
+} while (0)
+
+#define CDL_DELETE(head,del)                                                                   \
+    CDL_DELETE2(head,del,prev,next)
+
+#define CDL_DELETE2(head,del,prev,next)                                                        \
+do {                                                                                           \
+  if ( ((head)==(del)) && ((head)->next == (head))) {                                          \
+      (head) = 0L;                                                                             \
+  } else {                                                                                     \
+     (del)->next->prev = (del)->prev;                                                          \
+     (del)->prev->next = (del)->next;                                                          \
+     if ((del) == (head)) (head)=(del)->next;                                                  \
+  }                                                                                            \
+} while (0) 
+
+#define CDL_FOREACH(head,el)                                                                   \
+    CDL_FOREACH2(head,el,next)
+
+#define CDL_FOREACH2(head,el,next)                                                             \
+    for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) 
+
+#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2)                                                    \
+    CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
+
+#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)                                         \
+  for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL);                                        \
+      (el) && ((tmp2)=(el)->next, 1);                                                          \
+      ((el) = (((el)==(tmp1)) ? 0L : (tmp2))))
+
+#define CDL_SEARCH_SCALAR(head,out,field,val)                                                  \
+    CDL_SEARCH_SCALAR2(head,out,field,val,next)
+
+#define CDL_SEARCH_SCALAR2(head,out,field,val,next)                                            \
+do {                                                                                           \
+    CDL_FOREACH2(head,out,next) {                                                              \
+      if ((out)->field == (val)) break;                                                        \
+    }                                                                                          \
+} while(0) 
+
+#define CDL_SEARCH(head,out,elt,cmp)                                                           \
+    CDL_SEARCH2(head,out,elt,cmp,next)
+
+#define CDL_SEARCH2(head,out,elt,cmp,next)                                                     \
+do {                                                                                           \
+    CDL_FOREACH2(head,out,next) {                                                              \
+      if ((cmp(out,elt))==0) break;                                                            \
+    }                                                                                          \
+} while(0) 
+
+#define CDL_REPLACE_ELEM(head, el, add)                                                        \
+do {                                                                                           \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ if ((el)->next == (el)) {                                                                     \
+  (add)->next = (add);                                                                         \
+  (add)->prev = (add);                                                                         \
+  (head) = (add);                                                                              \
+ } else {                                                                                      \
+  (add)->next = (el)->next;                                                                    \
+  (add)->prev = (el)->prev;                                                                    \
+  (add)->next->prev = (add);                                                                   \
+  (add)->prev->next = (add);                                                                   \
+  if ((head) == (el)) {                                                                        \
+   (head) = (add);                                                                             \
+  }                                                                                            \
+ }                                                                                             \
+} while (0)
+
+#define CDL_PREPEND_ELEM(head, el, add)                                                        \
+do {                                                                                           \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ (add)->next = (el);                                                                           \
+ (add)->prev = (el)->prev;                                                                     \
+ (el)->prev = (add);                                                                           \
+ (add)->prev->next = (add);                                                                    \
+ if ((head) == (el)) {                                                                         \
+  (head) = (add);                                                                              \
+ }                                                                                             \
+} while (0)                                                                                    \
+
+#endif /* UTLIST_H */
+
diff --git a/minix/llvm/include/magic.h b/minix/llvm/include/magic.h
new file mode 100644 (file)
index 0000000..9bbca57
--- /dev/null
@@ -0,0 +1,1209 @@
+#ifndef _MAGIC_H
+#define _MAGIC_H
+
+#include <magic_def.h>
+#include <magic_common.h>
+#include <magic_structs.h>
+#include <magic_sentry.h>
+#include <magic_selement.h>
+#include <magic_range.h>
+#include <magic_eval.h>
+
+#include <stdio.h>
+#include <stddef.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Magic type macros. */
+#define MAGIC_TYPE_WALK_STOP                    1
+#define MAGIC_TYPE_WALK_SKIP_PATH               2
+#define MAGIC_TYPE_WALK_CONTINUE                3
+
+#define MAGIC_TYPE_WALK_UNIONS_AS_VOID          0x1
+#define MAGIC_TYPE_WALK_DEFAULT_FLAGS           (MAGIC_TYPE_WALK_UNIONS_AS_VOID)
+
+#define MAGIC_TYPE_COMPARE_VALUE_SET            0x01
+#define MAGIC_TYPE_COMPARE_FLAGS                0x02
+#define MAGIC_TYPE_COMPARE_NAME                 0x04
+#define MAGIC_TYPE_COMPARE_NAMES                0x08
+#define MAGIC_TYPE_COMPARE_MEMBER_NAMES         0x10
+#define MAGIC_TYPE_COMPARE_MEMBER_OFFSETS       0x20
+#define MAGIC_TYPE_COMPARE_ALL (MAGIC_TYPE_COMPARE_VALUE_SET |                 \
+    MAGIC_TYPE_COMPARE_FLAGS | MAGIC_TYPE_COMPARE_NAME |                       \
+    MAGIC_TYPE_COMPARE_NAMES | MAGIC_TYPE_COMPARE_MEMBER_NAMES |               \
+    MAGIC_TYPE_COMPARE_MEMBER_OFFSETS)
+
+#define MAGIC_TYPE_IS_WALKABLE(T) ((T)->type_id == MAGIC_TYPE_ARRAY            \
+    || (T)->type_id == MAGIC_TYPE_VECTOR || (T)->type_id == MAGIC_TYPE_UNION   \
+    || (T)->type_id == MAGIC_TYPE_STRUCT)
+#define MAGIC_TYPE_NUM_CONTAINED_TYPES(T)                                      \
+    ((T)->type_id == MAGIC_TYPE_ARRAY ? 1 : (T)->num_child_types)
+
+#define MAGIC_TYPE_IS_VOID(T) ((T)->type_id == MAGIC_TYPE_VOID                 \
+    || ( ((T)->flags & MAGIC_TYPE_EXTERNAL) && !strcmp((T)->type_str, "i8") ))
+#define MAGIC_TYPE_IS_RAW_ARRAY(T)                                             \
+    (((T)->type_id == MAGIC_TYPE_ARRAY                                         \
+    && (T)->contained_types[0]->type_id == MAGIC_TYPE_VOID)                    \
+    || (T)->type_id == MAGIC_TYPE_UNION)
+#define MAGIC_TYPE_IS_INT_ARRAY(T)                                             \
+    ((T)->type_id == MAGIC_TYPE_ARRAY                                          \
+    && (T)->contained_types[0]->type_id == MAGIC_TYPE_INTEGER)
+
+#define MAGIC_EXPAND_TYPE_STR               0x1
+#define MAGIC_SKIP_COMP_TYPES               0x2
+#define MAGIC_EXPAND_SENTRY                 0x4
+
+#define MAGIC_TYPE_STR_PRINT_LLVM_TYPES     0x01
+#define MAGIC_TYPE_STR_PRINT_SOURCE_TYPES   0x02
+#define MAGIC_TYPE_STR_PRINT_MEMBER_NAMES   0x04
+#define MAGIC_TYPE_STR_PRINT_SKIP_UNIONS    0x08
+#define MAGIC_TYPE_STR_PRINT_SKIP_STRUCTS   0x10
+#define MAGIC_TYPE_STR_PRINT_MULTI_NAMES    0x20
+#define MAGIC_TYPE_STR_PRINT_STYLE_DEFAULT                                     \
+    (MAGIC_TYPE_STR_PRINT_LLVM_TYPES | MAGIC_TYPE_STR_PRINT_SOURCE_TYPES |     \
+    MAGIC_TYPE_STR_PRINT_MEMBER_NAMES)
+
+#define MAGIC_TYPE_STR_PRINT_DEBUG          MAGIC_DEBUG_SET(0)
+
+#define MAGIC_TYPE_HAS_COMP_TYPES(T)        ((T)->compatible_types != NULL)
+#define MAGIC_TYPE_HAS_COMP_TYPE(T, I)                                         \
+    ((T)->compatible_types[(I)] != NULL)
+#define MAGIC_TYPE_COMP_TYPE(T, I)          ((T)->compatible_types[(I)])
+#define MAGIC_TYPE_NUM_COMP_TYPES(T, NUM)                                      \
+    do {                                                                       \
+        *(NUM) = 0;                                                            \
+        while(MAGIC_TYPE_HAS_COMP_TYPE(T, (*(NUM))++));                        \
+        (*(NUM))--;                                                            \
+    } while(0)
+#define MAGIC_TYPE_HAS_VALUE_SET(T)         ((T)->value_set != NULL)
+#define MAGIC_TYPE_HAS_VALUE(T, I)          ((I) < ((int*)(T)->value_set)[0])
+#define MAGIC_TYPE_VALUE(T, I)              (((int*)(T)->value_set)[(I)+1])
+#define MAGIC_TYPE_NUM_VALUES(T, NUM)       (*(NUM) = ((int*)(T)->value_set)[0])
+#define MAGIC_TYPE_HAS_MULTI_NAMES(T)       ((T)->num_names > 1)
+
+#define MAGIC_TYPE_FLAG(T,F) (((T)->flags & (F)) != 0)
+#define MAGIC_TYPE_ID(T) ((T)->id)
+#define MAGIC_TYPE_IS_STRING(T) (MAGIC_TYPE_FLAG(T,MAGIC_TYPE_EXTERNAL)        \
+    && (T)->type_id == MAGIC_TYPE_ARRAY                                        \
+    && !strcmp((T)->contained_types[0]->type_str, "i8"))
+#define MAGIC_TYPE_PRINT(T, FLAGS) do {                                        \
+        _magic_printf("TYPE: (id=%5d, name=%s, size=%d, num_child_types=%d, "  \
+            "type_id=%d, bit_width=%d, flags(ERDIVvUP)=%d%d%d%d%d%d%d%d, "     \
+            "values='", MAGIC_TYPE_ID(T), (T)->name, (T)->size,                \
+            (T)->num_child_types, (T)->type_id, (T)->bit_width,                \
+            MAGIC_TYPE_FLAG(T,MAGIC_TYPE_EXTERNAL),                            \
+            MAGIC_TYPE_FLAG(T,MAGIC_TYPE_IS_ROOT),                             \
+            MAGIC_TYPE_FLAG(T,MAGIC_TYPE_DYNAMIC),                             \
+            MAGIC_TYPE_FLAG(T,MAGIC_TYPE_INT_CAST),                            \
+            MAGIC_TYPE_FLAG(T,MAGIC_TYPE_STRICT_VALUE_SET),                    \
+            MAGIC_TYPE_FLAG(T,MAGIC_TYPE_VARSIZE),                             \
+            MAGIC_TYPE_FLAG(T,MAGIC_TYPE_UNSIGNED),                            \
+            MAGIC_TYPE_FLAG(T,MAGIC_TYPE_NO_INNER_PTRS));                      \
+        if(MAGIC_TYPE_HAS_VALUE_SET(T)) magic_type_values_print(T);            \
+        if(MAGIC_TYPE_HAS_MULTI_NAMES(T)) {                                    \
+            _magic_printf("', names='");                                       \
+            magic_type_names_print(T);                                         \
+        }                                                                      \
+        _magic_printf("', type_str=");                                         \
+        if((FLAGS) & MAGIC_EXPAND_TYPE_STR) magic_type_str_print(T);           \
+        else _magic_printf("%s", (T)->type_str ? (T)->type_str : "");          \
+        if(MAGIC_TYPE_HAS_COMP_TYPES(T)) {                                     \
+            _magic_printf(", comp_types=(");                                   \
+            magic_type_comp_types_print(T, FLAGS);                             \
+            _magic_printf(")");                                                \
+        }                                                                      \
+        _magic_printf(")");                                                    \
+    } while(0)
+
+#define MAGIC_TYPE_VARSIZE_EL_TYPE(T)                                          \
+    (T)->contained_types[(T)->num_child_types - 1]->contained_types[0]
+
+#define MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(AT,T,CT,S,VSN) do {                  \
+        assert(((S) && ((S) % (T)->size == 0 || VSN)) && "Bad size!");         \
+        (AT)->id = MAGIC_ID_NONE;                                              \
+        (AT)->flags |= MAGIC_TYPE_DYNAMIC;                                     \
+        (AT)->type_id = MAGIC_TYPE_ARRAY;                                      \
+        (AT)->size = S;                                                        \
+        (AT)->num_child_types = (S)/(T)->size;                                 \
+        (AT)->contained_types = CT;                                            \
+        (AT)->contained_types[0] = T;                                          \
+        if(VSN) {                                                              \
+            (AT)->flags |= MAGIC_TYPE_VARSIZE;                                 \
+            (AT)->num_child_types = VSN;                                       \
+        }                                                                      \
+    } while(0)
+#define MAGIC_TYPE_ARRAY_CREATE_FROM_N(AT,T,CT,N)                              \
+    MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(AT,T,CT,(T)->size*N, 0)
+
+#define MAGIC_TYPE_VOID_ARRAY_GET_FROM_SIZE(AT,S) do {                         \
+        *(AT) = *MAGIC_VOID_ARRAY_TYPE;                                        \
+        MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(AT,MAGIC_VOID_TYPE,                  \
+            MAGIC_VOID_ARRAY_TYPE->contained_types,S,0);                       \
+    } while(0)
+#define MAGIC_TYPE_VOID_ARRAY_GET_FROM_N(AT,N)                                 \
+    MAGIC_TYPE_VOID_ARRAY_GET_FROM_SIZE(AT,MAGIC_VOID_TYPE->size*N)
+
+#define MAGIC_TYPE_PTRINT_ARRAY_GET_FROM_SIZE(AT,S) do {                       \
+        *(AT) = *MAGIC_PTRINT_ARRAY_TYPE;                                      \
+        MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(AT,MAGIC_PTRINT_TYPE,                \
+            MAGIC_PTRINT_ARRAY_TYPE->contained_types,S,0);                     \
+    } while(0)
+#define MAGIC_TYPE_PTRINT_ARRAY_GET_FROM_N(AT,N)                               \
+    MAGIC_TYPE_PTRINT_ARRAY_GET_FROM_SIZE(AT,MAGIC_PTRINT_TYPE->size*N)
+
+#define MAGIC_TYPE_INT_CREATE(T,S,N,B) do {                                    \
+        (T)->id = MAGIC_ID_NONE;                                               \
+        (T)->flags |= MAGIC_TYPE_DYNAMIC;                                      \
+        (T)->type_id = MAGIC_TYPE_INTEGER;                                     \
+        (T)->size = S;                                                         \
+        (T)->num_child_types = 0;                                              \
+        (T)->contained_types = NULL;                                           \
+        (T)->bit_width = (S)*8;                                                \
+        (T)->name = N;                                                         \
+        sprintf(B, "i%d", (T)->bit_width);                                     \
+        (T)->type_str = B;                                                     \
+    } while(0)
+
+#define MAGIC_TYPE_COMP_ITER(TYPE,COMP_TYPE,DO) do {                           \
+        if(MAGIC_TYPE_HAS_COMP_TYPES(TYPE)) {                                  \
+            int __i = 0;                                                       \
+            while(MAGIC_TYPE_HAS_COMP_TYPE(TYPE, __i)) {                       \
+                COMP_TYPE=MAGIC_TYPE_COMP_TYPE(TYPE, __i);                     \
+                DO                                                             \
+                __i++;                                                         \
+            }                                                                  \
+        }                                                                      \
+    } while(0)
+
+/* Magic function macros. */
+#define MAGIC_FUNCTION_PARENT(F)                                               \
+    (MAGIC_STATE_FLAG(F,MAGIC_STATE_DYNAMIC) ?                                 \
+        MAGIC_DFUNCTION_FROM_FUNCTION(F)->parent_name : "")
+#define MAGIC_FUNCTION_ID(F) ((F)->id)
+#define MAGIC_FUNCTION_PRINT(F, EXPAND_TYPE_STR) do {                          \
+        _magic_printf("FUNCTION: (id=%5lu, name=%s, parent=%s, address=0x%08x,"\
+            " flags(RLDCdTArwxEI)=%c%c%d%d%d%d%d%d%d%d%d%d, type=",            \
+            (unsigned long)MAGIC_FUNCTION_ID(F), (F)->name,                    \
+            MAGIC_FUNCTION_PARENT(F), (unsigned) (F)->address,                 \
+            MAGIC_STATE_REGION_C(F), MAGIC_STATE_LIBSPEC_C(F),                 \
+            MAGIC_STATE_FLAG(F,MAGIC_STATE_DIRTY),                             \
+            MAGIC_STATE_FLAG(F,MAGIC_STATE_CONSTANT),                          \
+            MAGIC_STATE_FLAG(F,MAGIC_STATE_DYNAMIC),                           \
+            MAGIC_STATE_FLAG(F,MAGIC_STATE_DETACHED),                          \
+            MAGIC_STATE_FLAG(F,MAGIC_STATE_ADDR_NOT_TAKEN),                    \
+            MAGIC_STATE_FLAG(F,MAGIC_STATE_MODE_R),                            \
+            MAGIC_STATE_FLAG(F,MAGIC_STATE_MODE_W),                            \
+            MAGIC_STATE_FLAG(F,MAGIC_STATE_MODE_X),                            \
+            MAGIC_STATE_FLAG(F,MAGIC_STATE_EXTERNAL),                          \
+            MAGIC_STATE_FLAG(F,MAGIC_STATE_IMMUTABLE));                        \
+        MAGIC_TYPE_PRINT((F)->type, EXPAND_TYPE_STR);                          \
+        _magic_printf(")");                                                    \
+    } while(0)
+
+/* Magic function hash macros. */
+#define MAGIC_FUNCTION_TO_HASH_EL(function, function_hash)                     \
+    do {                                                                       \
+        function_hash->key = function->address;                                \
+        function_hash->function = function;                                    \
+    } while (0)
+
+#define MAGIC_DFUNCTION_TO_HASH_EL(dfunction, function, function_hash)         \
+    do {                                                                       \
+        function_hash->key = function->address;                                \
+        function_hash->function = function;                                    \
+    } while (0)
+
+/* Estimated maximum number of buckets needed. Increase as necessary. */
+#define MAGIC_FUNCTION_ADDR_EST_MAX_BUCKETS 32768
+/*
+ * Since we don't support freeing memory, we need to allocate _all_ the
+ * intermediate buckets as well. For simplicity, just assume 1 + 2 + 4 + ...
+ * + 2^n, though it will probably be less than that.
+ */
+#define MAGIC_FUNCTION_ADDR_EST_TOTAL_BUCKETS                                  \
+    ((MAGIC_FUNCTION_ADDR_EST_MAX_BUCKETS << 1) - 1)
+#define MAGIC_FUNCTION_ADDR_HASH_OVERHEAD                                      \
+    (MAGIC_FUNCTION_ADDR_EST_TOTAL_BUCKETS * sizeof(UT_hash_bucket) +          \
+    sizeof(UT_hash_table))
+
+/* Magic dynamic function macros. */
+#define MAGIC_DFUNCTION_PREV(DF)          ((DF)->prev)
+#define MAGIC_DFUNCTION_HAS_PREV(DF)      ((DF)->prev != NULL)
+#define MAGIC_DFUNCTION_NEXT(DF)          ((DF)->next)
+#define MAGIC_DFUNCTION_HAS_NEXT(DF)      ((DF)->next != NULL)
+#define MAGIC_DFUNCTION_TO_FUNCTION(DF)   (&((DF)->function))
+#define MAGIC_DFUNCTION_FROM_FUNCTION(F)                                       \
+    ((struct _magic_dfunction*)(((char*)(F)) -                                 \
+    offsetof(struct _magic_dfunction, function)))
+
+#define MAGIC_DFUNCTION_MNUM              (~(0xFEE1DEAF))
+#define MAGIC_DFUNCTION_MNUM_NULL         0
+
+#define MAGIC_DFUNCTION_MNUM_OK(D) ((D)->magic_number == MAGIC_DFUNCTION_MNUM)
+
+#define MAGIC_DFUNCTION_PRINT(DF, EXPAND_TYPE_STR) do {                        \
+        _magic_printf("DFUNCTION: (~mnum=%08x, address=0x%08x, prev=0x%08x, "  \
+            "next=0x%08x, function=", ~((DF)->magic_number), (unsigned) (DF),  \
+            (unsigned) (DF)->prev, (unsigned) (DF)->next);                     \
+        MAGIC_FUNCTION_PRINT(MAGIC_DFUNCTION_TO_FUNCTION(DF), EXPAND_TYPE_STR);\
+        _magic_printf(")");                                                    \
+    } while(0)
+
+#define MAGIC_DFUNCTION_ITER(HEAD, DFUNC, DO) do {                             \
+        if(HEAD) {                                                             \
+            DFUNC = NULL;                                                      \
+            while(!DFUNC || MAGIC_DFUNCTION_HAS_NEXT(DFUNC)) {                 \
+                DFUNC = !DFUNC ? HEAD : MAGIC_DFUNCTION_NEXT(DFUNC);           \
+                assert(magic_check_dfunction(DFUNC, 0)                         \
+                    && "Bad magic dfunction looked up!");                      \
+                DO                                                             \
+            }                                                                  \
+        }                                                                      \
+    } while(0)
+
+#define MAGIC_DFUNCTION_FUNC_ITER(HEAD, DFUNC, FUNC, DO)                       \
+        MAGIC_DFUNCTION_ITER(HEAD, DFUNC,                                      \
+            FUNC = MAGIC_DFUNCTION_TO_FUNCTION(DFUNC);                         \
+            DO                                                                 \
+        );
+
+/* Magic dynamic state index macros. */
+#define MAGIC_DSINDEX_ID(I) ((I) - _magic_dsindexes + 1)
+#define MAGIC_DSINDEX_IS_ALLOC(I)                                              \
+    ((I) && !MAGIC_STATE_FLAG(I, MAGIC_STATE_STACK))
+#define MAGIC_DSINDEX_PRINT(I, EXPAND_TYPE_STR) do {                           \
+        _magic_printf("DSINDEX: (id=%5d, name=%s, parent=%s, "                 \
+        "flags(SHMs)=%d%d%d%d type=",                                          \
+            MAGIC_DSINDEX_ID(I), (I)->name, (I)->parent_name,                  \
+            MAGIC_STATE_FLAG((I), MAGIC_STATE_STACK), MAGIC_STATE_FLAG((I),    \
+            MAGIC_STATE_HEAP), MAGIC_STATE_FLAG((I), MAGIC_STATE_MAP),         \
+            MAGIC_STATE_FLAG((I), MAGIC_STATE_SHM));                           \
+        MAGIC_TYPE_PRINT((I)->type, EXPAND_TYPE_STR);                          \
+        _magic_printf(")");                                                    \
+    } while(0)
+
+/* Magic dynamic state entry macros. */
+#define MAGIC_DSENTRY_PREV(DE)                  ((DE)->prev)
+#define MAGIC_DSENTRY_HAS_PREV(DE)              ((DE)->prev != NULL)
+#define MAGIC_DSENTRY_NEXT(DE)                  ((DE)->next)
+#define MAGIC_DSENTRY_HAS_NEXT(DE)              ((DE)->next != NULL)
+#define MAGIC_DSENTRY_HAS_EXT(DE)                                              \
+    ((DE)->ext && MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(DE),                \
+    MAGIC_STATE_EXT))
+#define MAGIC_DSENTRY_TO_SENTRY(DE)             (&((DE)->sentry))
+#define MAGIC_DSENTRY_FROM_SENTRY(E)                                           \
+    ((struct _magic_dsentry*)(((char*)(E)) -                                   \
+    offsetof(struct _magic_dsentry, sentry)))
+#define MAGIC_DSENTRY_TO_TYPE_ARR(DE)           ((DE)->type_array)
+#define MAGIC_DSENTRY_NEXT_MEMPOOL(DE)          ((DE)->next_mpool)
+#define MAGIC_DSENTRY_NEXT_MEMBLOCK(DE)         ((DE)->next_mblock)
+#define MAGIC_DSENTRY_HAS_NEXT_MEMPOOL(DE)      ((DE)->next_mpool != NULL)
+#define MAGIC_DSENTRY_HAS_NEXT_MEMBLOCK(DE)     ((DE)->next_mblock != NULL)
+
+#define MAGIC_DSENTRY_MSTATE_ALIVE              (~(0xFEE1DEAD))
+#define MAGIC_DSENTRY_MSTATE_DEAD               0xFEE1DEAD
+#define MAGIC_DSENTRY_MSTATE_FREED              0xDEADBEEF
+#define MAGIC_DSENTRY_MNUM                      MAGIC_DSENTRY_MSTATE_ALIVE
+#define MAGIC_DSENTRY_MNUM_NULL                 0
+#define MAGIC_DSENTRY_SITE_ID_NULL              0
+
+#define MAGIC_DSENTRY_MNUM_OK(D) ((D)->magic_number == MAGIC_DSENTRY_MNUM)
+#define MAGIC_DSENTRY_MSTATE_OK(D)                                             \
+    ((D)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE                            \
+    || (D)->magic_state == MAGIC_DSENTRY_MSTATE_DEAD                           \
+    || (D)->magic_state == MAGIC_DSENTRY_MSTATE_FREED)
+#define MAGIC_DSENTRY_MSTATE_C(D)                                              \
+    ((D)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE ? 'A'                      \
+    : (D)->magic_state == MAGIC_DSENTRY_MSTATE_DEAD ? 'D'                      \
+    : (D)->magic_state == MAGIC_DSENTRY_MSTATE_FREED ? 'F' : '?')
+
+#define MAGIC_DSENTRY_PRINT(DE, EXPAND_TYPE_STR) do {                          \
+        _magic_printf("DSENTRY: (~mnum=%08x, mstate=%c, address=0x%08x, "      \
+            "site_id=" MAGIC_ID_FORMAT ", next=0x%08x, sentry=",               \
+            ~((DE)->magic_number), MAGIC_DSENTRY_MSTATE_C(DE), (unsigned) (DE),\
+            (DE)->site_id, (unsigned) (DE)->next);                             \
+        MAGIC_SENTRY_PRINT(MAGIC_DSENTRY_TO_SENTRY(DE), EXPAND_TYPE_STR);      \
+        _magic_printf(")");                                                    \
+    } while(0)
+
+/* Iterate through all the top-level dsentries. */
+#define MAGIC_DSENTRY_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) do {           \
+        if(HEAD) {                                                             \
+            DSENTRY=NULL;                                                      \
+            while(!DSENTRY || MAGIC_DSENTRY_HAS_NEXT(DSENTRY)) {               \
+                PREV_DSENTRY = DSENTRY;                                        \
+                DSENTRY = !DSENTRY ? HEAD : MAGIC_DSENTRY_NEXT(DSENTRY);       \
+                assert(magic_check_dsentry(DSENTRY, 0)                         \
+                    && "Bad magic dsentry looked up!");                        \
+                SENTRY = MAGIC_DSENTRY_TO_SENTRY(DSENTRY);                     \
+                DO                                                             \
+            }                                                                  \
+        }                                                                      \
+    } while(0)
+
+#define MAGIC_DSENTRY_ALIVE_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) do {     \
+        MAGIC_DSENTRY_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,                   \
+            if((DSENTRY)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE) {       \
+                DO                                                             \
+            }                                                                  \
+        );                                                                     \
+    } while(0)
+
+/* Iterate through all the top-level dsentries and nest at the block level. */
+#define MAGIC_DSENTRY_NESTED_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) do {  \
+        MAGIC_DSENTRY_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,                  \
+            DO                                                                 \
+            if(magic_lookup_nested_dsentries                                  \
+                && MAGIC_STATE_FLAG(SENTRY, MAGIC_STATE_MEMPOOL)) {           \
+                struct _magic_dsentry *MEMPOOL_DSENTRY = DSENTRY;             \
+                MAGIC_DSENTRY_MEMBLOCK_ITER(MEMPOOL_DSENTRY, DSENTRY, SENTRY, \
+                    DO                                                         \
+                );                                                             \
+                DSENTRY = MEMPOOL_DSENTRY;                                     \
+            }                                                                  \
+        );                                                                     \
+    } while(0)
+
+#define MAGIC_DSENTRY_ALIVE_NESTED_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) \
+    do {                                                                      \
+        MAGIC_DSENTRY_NESTED_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,           \
+            if((DSENTRY)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE) {       \
+                DO                                                             \
+            }                                                                  \
+        );                                                                     \
+    } while(0)
+
+/* Iterate through all the block-level dsentries. */
+#define MAGIC_DSENTRY_BLOCK_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) do {   \
+        MAGIC_DSENTRY_NESTED_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,           \
+            if(!MAGIC_STATE_FLAG(SENTRY, MAGIC_STATE_MEMPOOL)) {              \
+                DO                                                             \
+            }                                                                  \
+        );                                                                     \
+    } while(0)
+
+#define MAGIC_DSENTRY_ALIVE_BLOCK_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) \
+    do {                                                                      \
+        MAGIC_DSENTRY_BLOCK_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,           \
+            if((DSENTRY)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE) {       \
+                DO                                                             \
+            }                                                                  \
+        );                                                                     \
+    } while(0)
+
+#define MAGIC_DSENTRY_MEMPOOL_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) do {   \
+        if(HEAD) {                                                             \
+            DSENTRY=NULL;                                                      \
+            while(!DSENTRY || MAGIC_DSENTRY_HAS_NEXT_MEMPOOL(DSENTRY)) {       \
+                PREV_DSENTRY = DSENTRY;                                        \
+                DSENTRY = !DSENTRY ? HEAD                                      \
+                    : MAGIC_DSENTRY_NEXT_MEMPOOL(DSENTRY);                     \
+                assert(magic_check_dsentry(DSENTRY, 0)                         \
+                    && "Bad magic dsentry looked up!");                        \
+                SENTRY = MAGIC_DSENTRY_TO_SENTRY(DSENTRY);                     \
+                DO                                                             \
+            }                                                                  \
+        }                                                                      \
+    } while(0)
+
+#define MAGIC_DSENTRY_MEMPOOL_ALIVE_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO)  \
+    do {                                                                       \
+        MAGIC_DSENTRY_MEMPOOL_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,           \
+            if((DSENTRY)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE) {         \
+                DO                                                             \
+            }                                                                  \
+        );                                                                     \
+    } while(0)
+
+#define MAGIC_DSENTRY_MEMBLOCK_ITER(MEMPOOL_DSENTRY,                           \
+    MEMBLOCK_DSENTRY,MEMBLOCK_SENTRY,DO)                                       \
+    do {                                                                       \
+        if(MEMPOOL_DSENTRY) {                                                  \
+            assert(magic_check_dsentry(MEMPOOL_DSENTRY, 0)                     \
+                && "Bad magic dsentry looked up!");                            \
+            assert(MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(MEMPOOL_DSENTRY),  \
+                MAGIC_STATE_MEMPOOL) && "Bad mempool dsentry looked up!");     \
+            MEMBLOCK_DSENTRY = MAGIC_DSENTRY_NEXT_MEMBLOCK(MEMPOOL_DSENTRY);   \
+            while (MEMBLOCK_DSENTRY && (MEMBLOCK_DSENTRY != MEMPOOL_DSENTRY)) {\
+                assert(magic_check_dsentry(MEMBLOCK_DSENTRY, 0)                \
+                    && "Bad magic dsentry looked up!");                        \
+                MEMBLOCK_SENTRY = MAGIC_DSENTRY_TO_SENTRY(MEMBLOCK_DSENTRY);   \
+                assert(MAGIC_STATE_FLAG(MEMBLOCK_SENTRY, MAGIC_STATE_MEMBLOCK) \
+                    && "Bad memblock dsentry looked up!");                     \
+                DO                                                             \
+                MEMBLOCK_DSENTRY=MAGIC_DSENTRY_NEXT_MEMBLOCK(MEMBLOCK_DSENTRY);\
+            }                                                                  \
+        }                                                                      \
+    } while(0)
+
+#define MAGIC_DSENTRY_MEMPOOL_LOOKUP(MEMBLOCK_DSENTRY,MEMPOOL_DSENTRY) do {    \
+        if (MEMBLOCK_DSENTRY) {                                                \
+            struct _magic_dsentry *DSENTRY;                                    \
+            struct _magic_sentry *SENTRY;                                      \
+            DSENTRY = MEMBLOCK_DSENTRY;                                        \
+            do {                                                               \
+                assert(magic_check_dsentry(DSENTRY, 0)                         \
+                    && "Bad magic dsentry looked up!");                        \
+                SENTRY = MAGIC_DSENTRY_TO_SENTRY(DSENTRY);                     \
+                if (MAGIC_STATE_FLAG(SENTRY, MAGIC_STATE_MEMPOOL)) {           \
+                    MEMPOOL_DSENTRY = DSENTRY;                                 \
+                    break;                                                     \
+                }                                                              \
+                DSENTRY = MAGIC_DSENTRY_NEXT_MEMBLOCK(DSENTRY);                \
+            } while (DSENTRY != MEMBLOCK_DSENTRY);                             \
+        }                                                                      \
+    } while(0)
+
+#define MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(HEAD, PREV_DSENTRY, DSENTRY, SENTRY,  \
+    PN, N, ID, DO) do {                                                        \
+        MAGIC_DSENTRY_ALIVE_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,             \
+            if((!(PN) || !strcmp((DSENTRY)->parent_name, (PN)))                \
+                && (!(N) || !strcmp((SENTRY)->name, (N)))                      \
+                && (!(ID) || ((ID) == (DSENTRY)->site_id))) {                  \
+                DO                                                             \
+            }                                                                  \
+        );                                                                     \
+    } while(0)
+
+#define MAGIC_DSENTRY_NUM(HEAD,NUM) do {                                       \
+        struct _magic_dsentry *_prev_dsentry, *_dsentry;                       \
+        struct _magic_sentry *_sentry;                                         \
+        *(NUM) = 0;                                                            \
+        MAGIC_DSENTRY_ITER(HEAD,_prev_dsentry,_dsentry,_sentry,(*(NUM))++;);   \
+    } while(0)
+
+#define MAGIC_DSENTRY_ALIVE_NUM(HEAD,NUM) do {                                 \
+        struct _magic_dsentry *_prev_dsentry, *_dsentry;                       \
+        struct _magic_sentry *_sentry;                                         \
+        *(NUM) = 0;                                                            \
+        MAGIC_DSENTRY_ALIVE_ITER(HEAD,_prev_dsentry,_dsentry,_sentry,(*(NUM))++;); \
+    } while(0)
+
+#define MAGIC_DSENTRY_BLOCK_NUM(HEAD,NUM) do {                                 \
+        struct _magic_dsentry *_prev_dsentry, *_dsentry;                       \
+        struct _magic_sentry *_sentry;                                         \
+        *(NUM) = 0;                                                            \
+        MAGIC_DSENTRY_BLOCK_ITER(HEAD,_prev_dsentry,_dsentry,_sentry,(*(NUM))++;); \
+    } while(0)
+
+#define MAGIC_DSENTRY_ALIVE_BLOCK_NUM(HEAD,NUM) do {                           \
+        struct _magic_dsentry *_prev_dsentry, *_dsentry;                       \
+        struct _magic_sentry *_sentry;                                         \
+        *(NUM) = 0;                                                            \
+        MAGIC_DSENTRY_ALIVE_BLOCK_ITER(HEAD,_prev_dsentry,_dsentry,_sentry,(*(NUM))++;); \
+    } while(0)
+
+#define MAGIC_DEAD_DSENTRIES_NEED_FREEING()                                    \
+    (magic_num_dead_dsentries > MAGIC_MAX_DEAD_DSENTRIES                       \
+    || magic_size_dead_dsentries > MAGIC_MAX_DEAD_DSENTRIES_SIZE)
+
+#define MAGIC_SENTRY_OVERLAPS(S, START, END) \
+    ((char*)(S)->address<=(char*)(END) \
+    && (char*)(S)->address+(S)->type->size-1>=(char*)(START))
+
+#define MAGIC_SENTRY_RANGE_ALIVE_BLOCK_ITER(SENTRY,START,END,DO) do { \
+        int __i; \
+        struct _magic_dsentry *__prev_dsentry, *__dsentry; \
+       if (magic_sentry_rl_index) { \
+           char *__addr = NULL; \
+           SENTRY = NULL; \
+           while (1) { \
+               __addr = __addr ? SENTRY->address : ((char*)END) + 1; \
+                SENTRY = magic_sentry_rl_pred_lookup(__addr); \
+                if (!SENTRY || !MAGIC_SENTRY_OVERLAPS(SENTRY, START, ((char*)-1))) break; \
+                DO \
+            } \
+            break; \
+        } \
+        for (__i=0;__i<_magic_sentries_num;__i++) { \
+            SENTRY = &_magic_sentries[__i]; \
+            if (MAGIC_SENTRY_OVERLAPS(SENTRY, START, END)) { DO } \
+        } \
+        MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, __prev_dsentry, __dsentry, SENTRY, \
+            if (MAGIC_SENTRY_OVERLAPS(SENTRY, START, END)) {                     \
+                if(magic_lookup_nested_dsentries                                  \
+                    && MAGIC_STATE_FLAG(SENTRY, MAGIC_STATE_MEMPOOL)) {           \
+                    struct _magic_dsentry *MEMPOOL_DSENTRY = __dsentry;           \
+                    struct _magic_dsentry *__dsentry2;                            \
+                    MAGIC_DSENTRY_MEMBLOCK_ITER(MEMPOOL_DSENTRY, __dsentry2, SENTRY, \
+                        if (MAGIC_SENTRY_OVERLAPS(SENTRY, START, END))  { DO } \
+                    );                                                          \
+                }                                                               \
+                else { DO }                                                    \
+            }                                                                   \
+        ); \
+    } while(0)
+
+/* Magic out-of-band dynamic state entry macros. */
+#define MAGIC_OBDSENTRY_TO_DSENTRY(OBDE)     (&((OBDE)->dsentry))
+#define MAGIC_OBDSENTRY_FROM_DSENTRY(DE)                                       \
+    ((struct _magic_obdsentry*)(((char*)(DE)) -                                \
+    offsetof(struct _magic_obdsentry, dsentry)))
+#define MAGIC_OBDSENTRY_TO_SENTRY(OBDE)                                        \
+    MAGIC_DSENTRY_TO_SENTRY(MAGIC_OBDSENTRY_TO_DSENTRY(OBDE))
+#define MAGIC_OBDSENTRY_FROM_SENTRY(E)                                         \
+    MAGIC_OBDSENTRY_FROM_DSENTRY(MAGIC_DSENTRY_FROM_SENTRY(E))
+#define MAGIC_OBDSENTRY_IS_FREE(OBDE)                                          \
+    ((OBDE)->dsentry.sentry.flags == 0)
+#define MAGIC_OBDSENTRY_FREE(OBDE)           ((OBDE)->dsentry.sentry.flags = 0)
+
+/* Magic memory pool state entry macros. */
+#define MAGIC_MPDESC_IS_FREE(POOL)        ((POOL)->is_alive == 0)
+#define MAGIC_MPDESC_ALLOC(POOL)          ((POOL)->is_alive = 1)
+#if MAGIC_MEM_USAGE_OUTPUT_CTL
+#define MAGIC_MPDESC_FREE(POOL) do {                                           \
+    (POOL)->is_alive = 0;                                                      \
+    (POOL)->addr = NULL;                                                       \
+    (POOL)->dtype_id = 0;                                                      \
+} while (0)
+#else
+#define MAGIC_MPDESC_FREE(POOL) do {                                           \
+    (POOL)->is_alive = 0;                                                      \
+    (POOL)->addr = NULL;                                                       \
+} while (0)
+#endif
+
+#define MAGIC_SELEMENT_MAX_PTR_RECURSIONS   100
+
+#define MAGIC_SELEMENT_NAME_PRINT(E) do {                                      \
+        if((E)->sentry) {                                                      \
+            magic_type_walk_root((E)->sentry->type, 0,                         \
+                (unsigned long) ((char*)(E)->address -                         \
+                (char*)(E)->sentry->address), magic_selement_name_print_cb,    \
+                (void*)(E));                                                   \
+        }                                                                      \
+        else {                                                                 \
+            _magic_printf("???");                                              \
+        }                                                                      \
+    } while(0)
+#define MAGIC_CHECK_TRG(T)                                                     \
+        (magic_type_target_walk(T, NULL, NULL, magic_type_count_cb, NULL) >= 0)
+#define MAGIC_SELEMENT_HAS_TRG(E)                                              \
+        ((E)->type->size == sizeof(void*)                                      \
+        && MAGIC_CHECK_TRG(*((void**)(E)->address)))
+#define MAGIC_SELEMENT_PRINT(E, FLAGS) do {                                    \
+        _magic_printf("SELEMENT: (parent=%s, num=%d, depth=%d, address=0x%08x,"\
+            " name=", (E)->sentry ? (E)->sentry->name : "???", (E)->num,       \
+            (E)->depth, (E)->address);                                         \
+        MAGIC_SELEMENT_NAME_PRINT(E);                                          \
+        _magic_printf(", type=");                                              \
+        if ((E)->type) MAGIC_TYPE_PRINT((E)->type, FLAGS);                     \
+        if(((FLAGS) & MAGIC_EXPAND_SENTRY) && (E)->sentry) {                   \
+            _magic_printf(", sentry=");                                        \
+            MAGIC_SENTRY_PRINT((E)->sentry, FLAGS);                            \
+        }                                                                      \
+        _magic_printf(")");                                                    \
+    } while(0)
+
+/* Magic external library descriptor macros. */
+#define MAGIC_LIBDESC_PRINT(LD)                                                \
+    _magic_printf("LIBDESC: (name=%s, text_range=[%p,%p], data_range=[%p,%p], "\
+        "alloc_address=%p, alloc_size=%zu)", (LD)->name, (LD)->text_range[0],  \
+        (LD)->text_range[1], (LD)->data_range[0], (LD)->data_range[1],         \
+        (LD)->alloc_address, (LD)->alloc_size);
+
+/* Magic SO library descriptor macros. */
+#define MAGIC_SODESC_PREV(SD)          ((SD)->prev)
+#define MAGIC_SODESC_HAS_PREV(SD)      ((SD)->prev != NULL)
+#define MAGIC_SODESC_NEXT(SD)          ((SD)->next)
+#define MAGIC_SODESC_HAS_NEXT(SD)      ((SD)->next != NULL)
+
+#define MAGIC_SODESC_PRINT(SD) do {                                            \
+        _magic_printf("SODESC: (address=%p, prev=%p, next=%p, ", (SD),         \
+        (SD)->prev, (SD)->next);                                               \
+        MAGIC_LIBDESC_PRINT(&((SD)->lib));                                     \
+        _magic_printf(")");                                                    \
+    } while(0)
+
+#define MAGIC_SODESC_ITER(HEAD, SODESC, DO) do {                               \
+        if (HEAD) {                                                            \
+            SODESC = NULL;                                                     \
+            while(!SODESC || MAGIC_SODESC_HAS_NEXT(SODESC)) {                  \
+                SODESC = !SODESC ? HEAD : MAGIC_SODESC_NEXT(SODESC);           \
+                DO                                                             \
+            }                                                                  \
+        }                                                                      \
+    } while(0)
+
+#define MAGIC_SODESC_ITER_SAFE(HEAD, SODESC, DO) do {                          \
+        struct _magic_sodesc *sodesc_next;                                     \
+        if (HEAD) {                                                            \
+            SODESC = NULL;                                                     \
+            while(!SODESC || sodesc_next != NULL) {                            \
+                SODESC = !SODESC ? HEAD : sodesc_next;                         \
+                sodesc_next = MAGIC_SODESC_NEXT(SODESC);                       \
+                DO                                                             \
+            }                                                                  \
+        }                                                                      \
+    } while(0)
+
+/* Magic DSO library descriptor macros. */
+#define MAGIC_DSODESC_PREV(DD)          ((DD)->prev)
+#define MAGIC_DSODESC_HAS_PREV(DD)      ((DD)->prev != NULL)
+#define MAGIC_DSODESC_NEXT(DD)          ((DD)->next)
+#define MAGIC_DSODESC_HAS_NEXT(DD)      ((DD)->next != NULL)
+
+#define MAGIC_DSODESC_PRINT(DD) do {                                           \
+        _magic_printf("DSODESC: (address=%p, prev=%p, next=%p, handle=%p, "    \
+            "ref_count=%d, ", (DD), (DD)->prev, (DD)->next, (DD)->handle,      \
+            (DD)->ref_count);                                                  \
+        MAGIC_LIBDESC_PRINT(&((DD)->lib));                                     \
+        _magic_printf(")");                                                    \
+    } while(0)
+
+#define MAGIC_DSODESC_ITER(HEAD, DSODESC, DO) do {                             \
+        if (HEAD) {                                                            \
+            DSODESC = NULL;                                                    \
+            while(!DSODESC || MAGIC_DSODESC_HAS_NEXT(DSODESC)) {               \
+                DSODESC = !DSODESC ? HEAD : MAGIC_DSODESC_NEXT(DSODESC);       \
+                DO                                                             \
+            }                                                                  \
+        }                                                                      \
+    } while(0)
+
+#define MAGIC_DSODESC_ITER_SAFE(HEAD, DSODESC, DO) do {                        \
+        struct _magic_dsodesc *dsodesc_next;                                   \
+        if (HEAD) {                                                            \
+            DSODESC = NULL;                                                    \
+            while(!DSODESC || dsodesc_next != NULL) {                          \
+                DSODESC = !DSODESC ? HEAD : dsodesc_next;                      \
+                dsodesc_next = MAGIC_DSODESC_NEXT(DSODESC);                    \
+                DO                                                             \
+            }                                                                  \
+        }                                                                      \
+    } while(0)
+
+/* Magic value casts. */
+#define MAGIC_VALUE_CAST_DEBUG MAGIC_DEBUG_SET(0)
+
+#define MAGIC_CHECKED_VALUE_SRC_CAST(SV, ST, DV, DT, RP, CS)                   \
+    do {                                                                       \
+        ST value = SV;                                                         \
+        DV = (DT) value;                                                       \
+        if (((ST) (DV)) != value) {                                            \
+            *(RP) = MAGIC_ERANGE;                                              \
+        }                                                                      \
+        else if(CS && value && (((DV) <= (DT) 0 && value >= (ST) 0) ||         \
+            ((DV) >= (DT) 0 && value <= (ST) 0))) {                            \
+            *(RP) = MAGIC_ESIGN;                                               \
+        }                                                                      \
+        if(MAGIC_VALUE_CAST_DEBUG) {                                           \
+            _magic_printf("SRC ");                                             \
+            MAGIC_SELEMENT_PRINT(src_selement, MAGIC_EXPAND_TYPE_STR);         \
+            _magic_printf("\n");                                               \
+            _magic_printf("DST ");                                             \
+            MAGIC_SELEMENT_PRINT(dst_selement, MAGIC_EXPAND_TYPE_STR);         \
+            _magic_printf("\n");                                               \
+            _magic_printf("MAGIC_CHECKED_VALUE_SRC_CAST: "                     \
+                "types=%s-->%s, value=", #ST, #DT);                            \
+            magic_selement_print_value(src_selement);                          \
+            _magic_printf("-->(long/unsigned long/void*)%d/%u/%08x, "          \
+                "ERANGE=%d, ESIGN=%d\n", (long) (DV), (unsigned long) (DV),    \
+                (unsigned long) (DV), *(RP) == MAGIC_ERANGE,                   \
+                *(RP) == MAGIC_ESIGN);                                         \
+        }                                                                      \
+    } while(0)
+
+#define MAGIC_CHECKED_VALUE_DST_CAST(SV, ST, DV, DT, RP)                       \
+    do {                                                                       \
+        DT value = (DT) SV;                                                    \
+        if (((ST) value) != (SV)) {                                            \
+            *(RP) = MAGIC_ERANGE;                                              \
+        }                                                                      \
+        *((DT*) (DV)) = value;                                                 \
+        if (MAGIC_VALUE_CAST_DEBUG) {                                          \
+            _magic_selement_t tmp_selement = *dst_selement;                    \
+            tmp_selement.address = DV;                                         \
+            _magic_printf("MAGIC_CHECKED_VALUE_DST_CAST: types=%s-->%s, "      \
+                "value=(long/unsigned long/void*)%d/%u/%08x-->", #ST, #DT,     \
+                (long) (SV), (unsigned long) (SV), (unsigned long) (SV));      \
+            magic_selement_print_value(&tmp_selement);                         \
+            _magic_printf(", ERANGE=%d\n", *(RP) == MAGIC_ERANGE);             \
+        }                                                                      \
+    } while(0)
+
+/* Magic utility macros. */
+#define MAGIC_ABS(X)                    ((X) >= 0 ? (X) : -(X))
+
+/* Magic page size. */
+#define MAGIC_PAGE_SIZE                 (magic_sys_pagesize ? magic_sys_pagesize : magic_get_sys_pagesize())
+EXTERN unsigned long magic_sys_pagesize;
+
+/* Magic sections. */
+#define MAGIC_DATA_SECTION_START        ((void*)&__start_magic_data)
+#define MAGIC_DATA_SECTION_END          ((void*)&__stop_magic_data)
+#define MAGIC_DATA_RO_SECTION_START     ((void*)&__start_magic_data_ro)
+#define MAGIC_DATA_RO_SECTION_END       ((void*)&__stop_magic_data_ro)
+#define MAGIC_ST_DATA_SECTION_START     ((void*)&__start_magic_data_st)
+#define MAGIC_ST_DATA_SECTION_END       ((void*)&__stop_magic_data_st)
+#define MAGIC_ST_DATA_RO_SECTION_START  ((void*)&__start_magic_data_st_ro)
+#define MAGIC_ST_DATA_RO_SECTION_END    ((void*)&__stop_magic_data_st_ro)
+#define MAGIC_TEXT_SECTION_START        ((void*)&__start_magic_functions)
+#define MAGIC_TEXT_SECTION_END          ((void*)&__stop_magic_functions)
+#define MAGIC_ST_TEXT_SECTION_START     ((void*)&__start_magic_functions_st)
+#define MAGIC_ST_TEXT_SECTION_END       ((void*)&__stop_magic_functions_st)
+EXTERN void* __start_magic_data;
+EXTERN void* __stop_magic_data;
+EXTERN void* __start_magic_data_ro;
+EXTERN void* __stop_magic_data_ro;
+EXTERN void* __start_magic_data_st;
+EXTERN void* __stop_magic_data_st;
+EXTERN void* __start_magic_data_st_ro;
+EXTERN void* __stop_magic_data_st_ro;
+EXTERN void* __start_magic_functions;
+EXTERN void* __stop_magic_functions;
+EXTERN void* __start_magic_functions_st;
+EXTERN void* __stop_magic_functions_st;
+
+#if MAGIC_THREAD_SAFE
+#if MAGIC_FORCE_LOCKS
+#define MAGIC_DSENTRY_LOCK()     magic_dsentry_lock(magic_dsentry_lock_args)
+#define MAGIC_DSENTRY_UNLOCK()   magic_dsentry_unlock(magic_dsentry_unlock_args)
+#define MAGIC_DFUNCTION_LOCK()   magic_dfunction_lock(magic_dfunction_lock_args)
+#define MAGIC_DFUNCTION_UNLOCK()                                               \
+    magic_dfunction_unlock(magic_dfunction_unlock_args)
+#define MAGIC_DSODESC_LOCK()     magic_dsodesc_lock(magic_dsodesc_lock_args)
+#define MAGIC_DSODESC_UNLOCK()   magic_dsodesc_unlock(magic_dsodesc_unlock_args)
+#define MAGIC_MPDESC_LOCK()      magic_mpdesc_lock(magic_mpdesc_lock_args)
+#define MAGIC_MPDESC_UNLOCK()    magic_mpdesc_unlock(magic_mpdesc_unlock_args)
+#else
+#define MAGIC_GENERIC_LOCK(LOCK,ARGS)                                          \
+    do {                                                                       \
+        int l;                                                                 \
+        if (LOCK) {                                                            \
+            l = LOCK(ARGS);                                                    \
+            assert(l == 0 && "bad lock");                                      \
+        }                                                                      \
+    } while (0)
+
+#define MAGIC_DSENTRY_LOCK()                                                   \
+    MAGIC_GENERIC_LOCK(magic_dsentry_lock,magic_dsentry_lock_args)
+#define MAGIC_DSENTRY_UNLOCK()                                                 \
+    MAGIC_GENERIC_LOCK(magic_dsentry_unlock,magic_dsentry_unlock_args)
+#define MAGIC_DFUNCTION_LOCK()                                                 \
+    MAGIC_GENERIC_LOCK(magic_dfunction_lock,magic_dfunction_lock_args)
+#define MAGIC_DFUNCTION_UNLOCK()                                               \
+    MAGIC_GENERIC_LOCK(magic_dfunction_unlock,magic_dfunction_unlock_args)
+#define MAGIC_DSODESC_LOCK()                                                   \
+    MAGIC_GENERIC_LOCK(magic_dsodesc_lock,magic_dsodesc_lock_args)
+#define MAGIC_DSODESC_UNLOCK()                                                 \
+    MAGIC_GENERIC_LOCK(magic_dsodesc_unlock,magic_dsodesc_unlock_args)
+#define MAGIC_MPDESC_LOCK()                                                    \
+    MAGIC_GENERIC_LOCK(magic_mpdesc_lock,magic_mpdesc_lock_args)
+#define MAGIC_MPDESC_UNLOCK()                                                  \
+    MAGIC_GENERIC_LOCK(magic_mpdesc_unlock,magic_mpdesc_unlock_args)
+#endif
+#define MAGIC_MULTIPLE_LOCK(DS, DF, DSO, MP)                                   \
+    do {                                                                       \
+        if (DS)                                                                \
+            MAGIC_DSENTRY_LOCK();                                              \
+        if (DF)                                                                \
+            MAGIC_DFUNCTION_LOCK();                                            \
+        if (DSO)                                                               \
+            MAGIC_DSODESC_LOCK();                                              \
+        if (MP)                                                                \
+            MAGIC_MPDESC_LOCK();                                               \
+    } while (0)
+#define MAGIC_MULTIPLE_UNLOCK(DS, DF, DSO, MP)                                 \
+    do {                                                                       \
+        if (MP)                                                                \
+            MAGIC_MPDESC_UNLOCK();                                             \
+        if (DSO)                                                               \
+            MAGIC_DSODESC_UNLOCK();                                            \
+        if (DF)                                                                \
+            MAGIC_DFUNCTION_UNLOCK();                                          \
+        if (DS)                                                                \
+            MAGIC_DSENTRY_UNLOCK();                                            \
+    } while (0)
+#define MAGIC_MULTIPLE_LOCK_BLOCK(DS, DF, DSO, MP, BLOCK)                      \
+    do {                                                                       \
+        MAGIC_MULTIPLE_LOCK(DS, DF, DSO, MP);                                  \
+        BLOCK                                                                  \
+        MAGIC_MULTIPLE_UNLOCK(DS, DF, DSO, MP);                                \
+    } while (0)
+#else
+#define MAGIC_DSENTRY_LOCK()
+#define MAGIC_DSENTRY_UNLOCK()
+#define MAGIC_DFUNCTION_LOCK()
+#define MAGIC_DFUNCTION_UNLOCK()
+#define MAGIC_DSODESC_LOCK()
+#define MAGIC_DSODESC_UNLOCK()
+#define MAGIC_MPDESC_LOCK()
+#define MAGIC_MPDESC_UNLOCK()
+#define MAGIC_MULTIPLE_LOCK(DS, DF, DSO, MP)
+#define MAGIC_MULTIPLE_UNLOCK(DS, DF, DSO, MP)
+#define MAGIC_MULTIPLE_LOCK_BLOCK(DS, DF, DSO, MP, BLOCK)                      \
+    do {                                                                       \
+        BLOCK                                                                  \
+    } while (0)
+#endif
+
+/* Debug. */
+#define MAGIC_DEBUG_HIGH        3
+#define MAGIC_DEBUG_AVG         2
+#define MAGIC_DEBUG_LOW         1
+#define MAGIC_DEBUG_NONE        0
+#define MAGIC_DEBUG                                                            \
+    MAGIC_DEBUG_SELECT(MAGIC_DEBUG_HIGH, MAGIC_DEBUG_NONE)
+
+#if MAGIC_DEBUG
+#define MAGIC_DEBUG_CODE(L, X)                                                 \
+    do {                                                                       \
+        if(L > MAGIC_DEBUG) break;                                             \
+        X                                                                      \
+    } while(0)
+#else
+#define MAGIC_DEBUG_CODE(L, X)
+#endif
+
+/* Magic Address Space Randomization (ASRPass) */
+#define _magic_asr_seed (_magic_vars->asr_seed)
+#define _magic_asr_heap_map_do_permutate (                                     \
+    _magic_vars->asr_heap_map_do_permutate)
+#define _magic_asr_heap_max_offset (_magic_vars->asr_heap_max_offset)
+#define _magic_asr_heap_max_padding (_magic_vars->asr_heap_max_padding)
+#define _magic_asr_map_max_offset_pages (_magic_vars->asr_map_max_offset_pages)
+#define _magic_asr_map_max_padding_pages (                                     \
+    _magic_vars->asr_map_max_padding_pages)
+
+/* Magic type array. */
+#define _magic_types                    (_magic_vars->types)
+#define _magic_types_num                (_magic_vars->types_num)
+#define _magic_types_next_id            (_magic_vars->types_next_id)
+
+/* Magic function array. */
+#define _magic_functions                (_magic_vars->functions)
+#define _magic_functions_num            (_magic_vars->functions_num)
+#define _magic_functions_next_id        (_magic_vars->functions_next_id)
+
+/* Magic dynamic function list. */
+#define _magic_first_dfunction          (_magic_vars->first_dfunction)
+#define _magic_last_dfunction           (_magic_vars->last_dfunction)
+#define _magic_dfunctions_num           (_magic_vars->dfunctions_num)
+
+/* Magic functions hash vars. */
+#define magic_function_hash_buff        (_magic_vars->function_hash_buff)
+#define magic_function_hash_buff_offset (_magic_vars->function_hash_buff_offset)
+#define magic_function_hash_buff_size   (_magic_vars->function_hash_buff_size)
+#define magic_function_hash_head        (_magic_vars->function_hash_head)
+
+/* Magic dynamic state index array. */
+#define _magic_dsindexes (_magic_vars->dsindexes)
+#define _magic_dsindexes_num (_magic_vars->dsindexes_num)
+
+/* Magic dynamic state entry list. */
+#define _magic_first_dsentry (_magic_vars->first_dsentry)
+#define magic_num_dead_dsentries (_magic_vars->num_dead_dsentries)
+#define magic_size_dead_dsentries (_magic_vars->size_dead_dsentries)
+
+/* Magic memory pool dynamic state entry list. */
+#define _magic_first_mempool_dsentry (_magic_vars->first_mempool_dsentry)
+
+/* Magic SO library descriptor list. */
+#define _magic_first_sodesc (_magic_vars->first_sodesc)
+#define _magic_last_sodesc (_magic_vars->last_sodesc)
+#define _magic_sodescs_num (_magic_vars->sodescs_num)
+
+/* Magic DSO library descriptor list. */
+#define _magic_first_dsodesc (_magic_vars->first_dsodesc)
+#define _magic_last_dsodesc (_magic_vars->last_dsodesc)
+#define _magic_dsodescs_num (_magic_vars->dsodescs_num)
+
+/* Magic stack-related variables. */
+#define _magic_first_stack_dsentry (_magic_vars->first_stack_dsentry)
+#define _magic_last_stack_dsentry (_magic_vars->last_stack_dsentry)
+
+/* Magic default stubs. */
+EXTERN struct _magic_type magic_default_type;
+EXTERN struct _magic_dsentry magic_default_dsentry;
+EXTERN struct _magic_dfunction magic_default_dfunction;
+EXTERN struct _magic_type magic_default_ret_addr_type;
+
+/* Magic vars references. */
+EXTERN struct _magic_vars_t _magic_vars_buff;
+EXTERN struct _magic_vars_t *_magic_vars;
+
+FUNCTION_BLOCK(
+
+/* Magic vars wrappers. */
+PUBLIC void *_magic_vars_addr();
+PUBLIC size_t _magic_vars_size();
+
+/* Magic printf. */
+PUBLIC int magic_null_printf(const char* format, ...);
+PUBLIC int magic_err_printf(const char* format, ...);
+PUBLIC void magic_set_printf(printf_ptr_t func_ptr);
+PUBLIC printf_ptr_t magic_get_printf(void);
+PUBLIC void magic_assert_failed(const char *assertion, const char *file,
+    const char *function, const int line);
+
+/* Magic utility functions. */
+PUBLIC unsigned long magic_get_sys_pagesize();
+
+/* Magic lock primitives. */
+typedef int (*magic_lock_t)(void*);
+typedef int (*magic_unlock_t)(void*);
+
+EXTERN magic_lock_t magic_dsentry_lock;
+EXTERN magic_unlock_t magic_dsentry_unlock;
+EXTERN void *magic_dsentry_lock_args;
+EXTERN void *magic_dsentry_unlock_args;
+
+EXTERN magic_lock_t magic_dfunction_lock;
+EXTERN magic_unlock_t magic_dfunction_unlock;
+EXTERN void *magic_dfunction_lock_args;
+EXTERN void *magic_dfunction_unlock_args;
+
+EXTERN magic_lock_t magic_dsodesc_lock;
+EXTERN magic_unlock_t magic_dsodesc_unlock;
+EXTERN void *magic_dsodesc_lock_args;
+EXTERN void *magic_dsodesc_unlock_args;
+
+EXTERN magic_lock_t magic_mpdesc_lock;
+EXTERN magic_unlock_t magic_mpdesc_unlock;
+EXTERN void *magic_mpdesc_lock_args;
+EXTERN void *magic_mpdesc_unlock_args;
+
+PUBLIC void magic_dsentry_set_lock_primitives(magic_lock_t lock,
+    magic_unlock_t unlock, void *lock_args, void *unlock_args);
+PUBLIC void magic_dfunction_set_lock_primitives(magic_lock_t lock,
+    magic_unlock_t unlock, void *lock_args, void *unlock_args);
+PUBLIC void magic_dsodesc_set_lock_primitives(magic_lock_t lock,
+    magic_unlock_t unlock, void *lock_args, void *unlock_args);
+PUBLIC void magic_mpdesc_set_lock_primitives(magic_lock_t lock,
+    magic_unlock_t unlock, void *lock_args, void *unlock_args);
+
+/*
+ * Magic void ptr and array (force at the least 1 void* and 1 void array in the
+ * list of globals).
+ */
+EXTERN void* MAGIC_VOID_PTR;
+EXTERN char MAGIC_VOID_ARRAY[1];
+
+/* Magic special types. */
+EXTERN struct _magic_type *MAGIC_VOID_PTR_TYPE;
+EXTERN struct _magic_type *MAGIC_VOID_PTR_INT_CAST_TYPE;
+EXTERN struct _magic_type *MAGIC_VOID_ARRAY_TYPE;
+EXTERN struct _magic_type *MAGIC_PTRINT_TYPE;
+EXTERN struct _magic_type *MAGIC_PTRINT_ARRAY_TYPE;
+
+/* Magic annotations. */
+EXTERN VOLATILE int MAGIC_CALL_ANNOTATION_VAR;
+
+/* Magic status variables. */
+EXTERN int magic_init_done;
+EXTERN int magic_libcommon_active;
+EXTERN int magic_lookup_nested_dsentries;
+EXTERN int magic_allow_dead_dsentries;
+EXTERN int magic_ignore_dead_dsentries;
+EXTERN int magic_mmap_dsentry_header_prot;
+EXTERN int _magic_enabled;
+EXTERN int _magic_checkpoint_enabled;
+EXTERN int _magic_lazy_checkpoint_enabled;
+
+/* Magic page size. */
+EXTERN unsigned long magic_sys_pagesize;
+
+/* Initialization functions. */
+PUBLIC void magic_init(void);
+PUBLIC void magic_stack_init();
+
+/* Dfunction functions. */
+PUBLIC int magic_check_dfunction(struct _magic_dfunction *ptr, int flags);
+PUBLIC int magic_check_dfunctions();
+PUBLIC int magic_check_dfunctions_safe();
+PUBLIC void magic_print_dfunction(struct _magic_dfunction *dfunction);
+PUBLIC void magic_print_dfunctions();
+PUBLIC void magic_print_dfunctions_safe();
+PUBLIC void magic_copy_dfunction(struct _magic_dfunction *dfunction,
+    struct _magic_dfunction *dst_dfunction);
+
+/* Dsindex functions. */
+PUBLIC void magic_print_dsindex(struct _magic_dsindex *dsindex);
+PUBLIC void magic_print_dsindexes();
+
+/* Dsentry functions. */
+PUBLIC int magic_check_dsentry(struct _magic_dsentry *ptr, int flags);
+PUBLIC int magic_check_dsentries();
+PUBLIC int magic_check_dsentries_safe();
+PUBLIC void magic_print_dsentry(struct _magic_dsentry *dsentry);
+PUBLIC void magic_print_dsentries();
+PUBLIC void magic_print_dsentries_safe();
+PUBLIC void magic_copy_dsentry(struct _magic_dsentry *dsentry,
+    struct _magic_dsentry *dst_dsentry);
+
+/* Sodesc functions. */
+PUBLIC void magic_print_sodesc(struct _magic_sodesc *sodesc);
+PUBLIC void magic_print_sodescs();
+
+/* Dsodesc functions. */
+PUBLIC void magic_print_dsodesc(struct _magic_dsodesc *dsodesc);
+PUBLIC void magic_print_dsodescs();
+PUBLIC void magic_print_dsodescs_safe();
+
+/* Section functions. */
+PUBLIC void magic_print_sections();
+
+/* Lookup functions. */
+PUBLIC struct _magic_sentry* magic_mempool_sentry_lookup_by_range(void *addr,
+    struct _magic_dsentry *dsentry_buff);
+PUBLIC struct _magic_dsindex* magic_dsindex_lookup_by_name(char *parent_name,
+    char *name);
+PUBLIC struct _magic_dsentry*
+    magic_dsentry_prev_lookup(struct _magic_dsentry* dsentry);
+PUBLIC struct _magic_dsentry*
+    magic_mempool_dsentry_prev_lookup(struct _magic_dsentry* dsentry);
+PUBLIC struct _magic_function* magic_function_lookup_by_id(_magic_id_t id,
+    struct _magic_dfunction *dfunction_buff);
+PUBLIC struct _magic_function* magic_function_lookup_by_addr(void *addr,
+    struct _magic_dfunction *dfunction_buff);
+PUBLIC struct _magic_function* magic_function_lookup_by_name(char *parent_name,
+    char *name);
+PUBLIC struct _magic_type* magic_type_lookup_by_name(char *name);
+PUBLIC struct _magic_dsodesc* magic_dsodesc_lookup_by_handle(void *handle);
+PUBLIC int magic_selement_lookup_by_name(char* name,
+    _magic_selement_t *selement, struct _magic_dsentry *dsentry_buff);
+
+/* Magic state function functions. */
+PUBLIC void magic_print_function(struct _magic_function *function);
+PUBLIC void magic_print_functions();
+
+/* Magic state function lookup hash functions. */
+PUBLIC void magic_function_hash_build(void *buff, size_t buff_size);
+PUBLIC void magic_function_hash_destroy(void);
+PUBLIC size_t magic_function_hash_estimate_buff_size(int functions_num);
+PUBLIC struct _magic_function *magic_function_lookup_by_addr_hash(void *addr,
+    struct _magic_dfunction *dfunction_buff);
+PUBLIC void *magic_function_hash_alloc(size_t size);
+PUBLIC void magic_function_hash_dealloc(void *object, size_t size);
+
+/* Magic state type functions. */
+PUBLIC void magic_print_type(const struct _magic_type* type);
+PUBLIC void magic_print_types();
+PUBLIC void magic_type_str_set_print_style(const int style);
+PUBLIC int magic_type_str_get_print_style();
+PUBLIC void magic_type_str_print(const struct _magic_type* type);
+PUBLIC void magic_type_values_print(const struct _magic_type* type);
+PUBLIC void magic_type_names_print(const struct _magic_type* type);
+PUBLIC void magic_type_comp_types_print(const struct _magic_type* type,
+    int flags);
+PUBLIC int magic_type_str_print_from_target(void* target);
+PUBLIC int magic_type_equals(const struct _magic_type* type,
+    const struct _magic_type* other_type);
+PUBLIC int magic_type_compatible(const struct _magic_type* type,
+    const struct _magic_type* other_type, int flags);
+PUBLIC int magic_type_comp_compatible(const struct _magic_type* type,
+    const struct _magic_type* other_type);
+PUBLIC int magic_type_ptr_is_text(const struct _magic_type* ptr_type);
+PUBLIC int magic_type_ptr_is_data(const struct _magic_type* ptr_type);
+PUBLIC int magic_type_alloc_needs_varsized_array(const struct _magic_type* type,
+    size_t alloc_size, int *num_elements);
+PUBLIC size_t
+magic_type_alloc_get_varsized_array_size(const struct _magic_type* type,
+    int num_elements);
+PUBLIC void magic_type_parse_varsized_array(const struct _magic_type *type,
+    const struct _magic_type **sub_struct_type,
+    const struct _magic_type **sub_array_type,
+    size_t *sub_array_offset,
+    size_t *sub_array_size);
+
+/* Magic type walk functions. */
+typedef int (*magic_type_walk_cb_t)(const struct _magic_type*, unsigned, int,
+    const struct _magic_type*, const unsigned, int, void*);
+PUBLIC int magic_type_walk_flags(const struct _magic_type* parent_type,
+    unsigned parent_offset, int child_num, const struct _magic_type* type,
+    unsigned offset, const unsigned min_offset, const unsigned max_offset,
+    const magic_type_walk_cb_t cb, void* cb_args, int flags);
+PUBLIC int magic_type_target_walk(void* target,
+    struct _magic_dsentry** trg_dsentry,
+    struct _magic_dfunction** trg_dfunction,
+    const magic_type_walk_cb_t cb, void* cb_args);
+PUBLIC int magic_type_walk_as_void_array(const struct _magic_type* parent_type,
+    unsigned parent_offset, int child_num, const struct _magic_type* type,
+    unsigned offset, const unsigned min_offset, const unsigned max_offset,
+    const magic_type_walk_cb_t cb, void* cb_args);
+PUBLIC int
+magic_type_walk_as_ptrint_array(const struct _magic_type* parent_type,
+    unsigned parent_offset, int child_num, const struct _magic_type* type,
+    void* offset_addr, unsigned offset, const unsigned min_offset,
+    const unsigned max_offset, const magic_type_walk_cb_t cb, void* cb_args);
+PUBLIC void magic_type_walk_step(const struct _magic_type *type,
+    int child_num, const struct _magic_type **child_type,
+    unsigned *child_offset, int walk_flags);
+
+/* Magic type walk callbacks. */
+PUBLIC int magic_type_str_print_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num, const struct _magic_type* type,
+    const unsigned offset, int depth, void* cb_args);
+PUBLIC int magic_selement_name_print_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num, const struct _magic_type* type,
+    const unsigned offset, int depth, void* cb_args);
+PUBLIC int magic_selement_name_get_cb(const struct _magic_type *parent_type,
+    const unsigned parent_offset, int child_num, const struct _magic_type *type,
+    const unsigned offset, int depth, void *args_array);
+PUBLIC int magic_type_count_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num, const struct _magic_type* type,
+    const unsigned offset, int depth, void* cb_args);
+PUBLIC int magic_type_child_offset_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num, const struct _magic_type* type,
+    const unsigned offset, int depth, void* cb_args);
+
+)
+
+/* Magic type walk helpers. */
+#define magic_type_walk(parent_type, parent_offset, child_num, type, offset,   \
+    min_offset, max_offset, cb, cb_args)                                       \
+    magic_type_walk_flags(parent_type, parent_offset, child_num, type, offset, \
+    min_offset, max_offset, cb, cb_args, MAGIC_TYPE_WALK_DEFAULT_FLAGS)
+#define magic_type_walk_root(type, min_offset, max_offset, cb, cb_args)        \
+    magic_type_walk(NULL, 0, 0, type, 0, min_offset, max_offset, cb, cb_args)
+#define magic_type_walk_root_at_offset(type, offset, cb, cb_args)              \
+    magic_type_walk_root(type, offset, offset, cb, cb_args)
+#define magic_type_walk_root_all(type, cb, cb_args)                            \
+    magic_type_walk_root(type, 0, ULONG_MAX, cb, cb_args)
+
+/* Magic size functions. */
+PUBLIC size_t magic_type_get_size(struct _magic_type *type, int flags);
+PUBLIC size_t magic_types_get_size(int flags);
+PUBLIC size_t magic_function_get_size(struct _magic_function *function,
+    int flags);
+PUBLIC size_t magic_functions_get_size(int flags);
+PUBLIC size_t magic_dfunctions_get_size(int flags);
+PUBLIC size_t magic_sentry_get_size(struct _magic_sentry *sentry, int flags);
+PUBLIC size_t magic_sentries_get_size(int flags);
+PUBLIC size_t magic_dsentries_get_size(int flags);
+PUBLIC size_t magic_dsindex_get_size(struct _magic_dsindex *dsindex,
+    int flags);
+PUBLIC size_t magic_dsindexes_get_size(int flags);
+PUBLIC size_t magic_sodesc_get_size(struct _magic_sodesc *sodesc,
+    int flags);
+PUBLIC size_t magic_sodescs_get_size(int flags);
+PUBLIC size_t magic_dsodesc_get_size(struct _magic_dsodesc *dsodesc,
+    int flags);
+PUBLIC size_t magic_dsodescs_get_size(int flags);
+PUBLIC size_t magic_metadata_get_size(int flags);
+PUBLIC size_t magic_sentries_data_get_size(int flags);
+PUBLIC size_t magic_dsentries_data_get_size(int flags);
+PUBLIC size_t magic_other_data_get_size(int flags);
+PUBLIC size_t magic_data_get_size(int flags);
+PUBLIC void magic_print_size_stats(int flags);
+
+#define MAGIC_SIZE_VALUE_SET                0x0001
+#define MAGIC_SIZE_NAMES                    0x0002
+#define MAGIC_SIZE_DSENTRY_NAMES            0x0004
+#define MAGIC_SIZE_DSINDEX_NAMES            0x0008
+#define MAGIC_SIZE_TYPE_NAMES               0x0010
+#define MAGIC_SIZE_MEMBER_NAMES             0x0020
+#define MAGIC_SIZE_COMP_TYPES               0x0040
+#define MAGIC_SIZE_ALL (MAGIC_SIZE_VALUE_SET | MAGIC_SIZE_NAMES |              \
+    MAGIC_SIZE_DSENTRY_NAMES | MAGIC_SIZE_DSINDEX_NAMES | MAGIC_SIZE_TYPE_NAMES\
+    | MAGIC_SIZE_MEMBER_NAMES | MAGIC_SIZE_COMP_TYPES)
+
+#endif
+
+/* Magic reentrant functions. */
+PUBLIC void magic_reentrant_enable(void);
+PUBLIC void magic_reentrant_disable(void);
diff --git a/minix/llvm/include/magic_analysis.h b/minix/llvm/include/magic_analysis.h
new file mode 100644 (file)
index 0000000..645a266
--- /dev/null
@@ -0,0 +1,427 @@
+#ifndef _MAGIC_ANALYSIS_H
+#define _MAGIC_ANALYSIS_H
+
+#include <magic.h>
+#include <magic_mem.h>
+
+/* Special convenience types. */
+#define MAGIC_TYPE_SPECIAL_INIT(STR) { 0, STR, NULL, 0, STR, 0, 0, 0, 0, 0, 0, \
+    0, MAGIC_TYPE_FUNCTION, MAGIC_TYPE_EXTERNAL, 0 }
+EXTERN char magic_ne_str[];
+EXTERN char magic_enf_str[];
+EXTERN char magic_bo_str[];
+EXTERN char magic_be_str[];
+EXTERN char magic_bv_str[];
+EXTERN char magic_vf_str[];
+EXTERN const struct _magic_type magic_NULL_ENTRY_TYPE;
+EXTERN const struct _magic_type magic_ENTRY_NOT_FOUND_TYPE;
+EXTERN const struct _magic_type magic_BAD_OFFSET_TYPE;
+EXTERN const struct _magic_type magic_BAD_ENTRY_TYPE;
+EXTERN const struct _magic_type magic_BAD_VALUE_TYPE;
+EXTERN const struct _magic_type magic_VALUE_FOUND;
+#define MAGIC_TYPE_NULL_ENTRY               (&magic_NULL_ENTRY_TYPE)
+#define MAGIC_TYPE_ENTRY_NOT_FOUND          (&magic_ENTRY_NOT_FOUND_TYPE)
+#define MAGIC_TYPE_BAD_OFFSET               (&magic_BAD_OFFSET_TYPE)
+#define MAGIC_TYPE_BAD_ENTRY                (&magic_BAD_ENTRY_TYPE)
+#define MAGIC_TYPE_BAD_VALUE                (&magic_BAD_VALUE_TYPE)
+#define MAGIC_TYPE_VALUE_FOUND              (&magic_VALUE_FOUND)
+#define MAGIC_TYPE_IS_SPECIAL(T) (T == MAGIC_TYPE_NULL_ENTRY                   \
+    || T == MAGIC_TYPE_ENTRY_NOT_FOUND || T == MAGIC_TYPE_BAD_OFFSET           \
+    || T == MAGIC_TYPE_BAD_ENTRY || T == MAGIC_TYPE_BAD_VALUE                  \
+    || T == MAGIC_TYPE_VALUE_FOUND)
+
+/* Magic state element macros. */
+#define MAGIC_SEL_ANALYZE_POINTERS          0x00001
+#define MAGIC_SEL_ANALYZE_NONPOINTERS       0x00002
+#define MAGIC_SEL_ANALYZE_LIKELYPOINTERS    0x00004
+#define MAGIC_SEL_ANALYZE_DATA              0x00008
+#define MAGIC_SEL_ANALYZE_INVARIANTS        0x00010
+#define MAGIC_SEL_ANALYZE_VIOLATIONS        0x00020
+#define MAGIC_SEL_ANALYZE_WALKABLE          0x00040
+#define MAGIC_SEL_ANALYZE_DYNAMIC           0x00080
+#define MAGIC_SEL_ANALYZE_OUT_OF_BAND       0x00100
+#define MAGIC_SEL_ANALYZE_LIB_SRC           0x00200
+#define MAGIC_SEL_ANALYZE_ALL                                                  \
+    (MAGIC_SEL_ANALYZE_POINTERS | MAGIC_SEL_ANALYZE_NONPOINTERS                \
+    | MAGIC_SEL_ANALYZE_DATA | MAGIC_SEL_ANALYZE_INVARIANTS                    \
+    | MAGIC_SEL_ANALYZE_VIOLATIONS | MAGIC_SEL_ANALYZE_WALKABLE                \
+    | MAGIC_SEL_ANALYZE_DYNAMIC | MAGIC_SEL_ANALYZE_OUT_OF_BAND                \
+    | MAGIC_SEL_ANALYZE_LIB_SRC)
+
+#define MAGIC_SEL_SKIP_UNIONS               0x00400
+#define MAGIC_SEL_SKIP_INTEGERS             0x00800
+#define MAGIC_SEL_ANALYZE_NONPTRS_AS_PTRS   0x01000
+#define MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS   0x02000
+
+#define MAGIC_SEL_FOUND_DATA                0x04000
+#define MAGIC_SEL_FOUND_INVARIANTS          0x08000
+#define MAGIC_SEL_FOUND_VIOLATIONS          0X10000
+#define MAGIC_SEL_FOUND_WALKABLE            0x20000
+
+/* Magic state element analyzed. */
+typedef enum {
+    _ptr_type_found,
+    _other_types_found,
+    _void_type_found,
+    _comp_trg_types_found,
+    _badentry_found
+} _magic_trg_stats_t;
+struct _magic_sel_analyzed_s {
+    unsigned type_id, contained_type_id;
+    int flags;
+    int num;
+    union {
+        struct {
+            void *value;
+            union {
+                struct _magic_dsentry dsentry;
+                struct _magic_dfunction dfunction;
+            } trg;
+            struct {
+                struct _magic_dsentry *dsentry;
+                struct _magic_dfunction *dfunction;
+            } trg_p;
+            int trg_flags;
+            int trg_offset;
+            _magic_selement_t trg_selements[MAGIC_MAX_RECURSIVE_TYPES + 1];
+            _magic_trg_stats_t trg_stats[MAGIC_MAX_RECURSIVE_TYPES + 1];
+            int first_legal_trg_type;
+            unsigned num_legal_trg_types;
+            unsigned num_trg_types;
+        } ptr;
+        struct {
+            int value;
+            int trg_flags;
+        } nonptr;
+    } u;
+};
+typedef struct _magic_sel_analyzed_s _magic_sel_analyzed_t;
+
+#define MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(E)                             \
+    (((E)->u.ptr.trg_flags & MAGIC_STATE_TEXT) != 0)
+#define MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(E)                               \
+    ((E)->u.ptr.trg_flags && !MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(E))
+#define MAGIC_SEL_ANALYZED_PTR_SENTRY(E)                                       \
+    ((E)->u.ptr.trg_flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)                 \
+    ? (E)->u.ptr.trg_p.dsentry->sentry                                         \
+    : (E)->u.ptr.trg.dsentry.sentry
+#define MAGIC_SEL_ANALYZED_PTR_SENTRY_ADDRESS(E)                               \
+    ((E)->u.ptr.trg_flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)                 \
+    ? &((E)->u.ptr.trg_p.dsentry->sentry)                                      \
+    : &((E)->u.ptr.trg.dsentry.sentry)
+#define MAGIC_SEL_ANALYZED_PTR_FUNCTION(E)                                     \
+    ((E)->u.ptr.trg_flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)                 \
+    ? (E)->u.ptr.trg_p.dfunction->function                                     \
+    : (E)->u.ptr.trg.dfunction.function
+#define MAGIC_SEL_ANALYZED_PTR_TRG_NAME(E)                                     \
+    (MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(E) ? ""                       \
+    : MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(E)                               \
+    ? (MAGIC_SEL_ANALYZED_PTR_FUNCTION(E)).name                                \
+    : (MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(E)                                \
+    ? (MAGIC_SEL_ANALYZED_PTR_SENTRY(E)).name : "?"))
+#define MAGIC_SEL_ANALYZED_PTR_TRG_ADDRESS(E)                                  \
+    (MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(E) ? NULL                     \
+    : MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(E)                               \
+    ? (MAGIC_SEL_ANALYZED_PTR_FUNCTION(E)).address                             \
+    : (MAGIC_SEL_ANALYZED_PTR_SENTRY(E)).address)
+#define MAGIC_SEL_ANALYZED_PTR_PRINT_TRG_ABS_NAME(E)                           \
+    do {                                                                       \
+        if (MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(E)                     \
+            || MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(E)) {                   \
+            _magic_printf(MAGIC_SEL_ANALYZED_PTR_TRG_NAME(E));                 \
+        } else {                                                               \
+            magic_print_sentry_abs_name(                                       \
+                MAGIC_SEL_ANALYZED_PTR_SENTRY_ADDRESS(E));                     \
+        }                                                                      \
+    } while(0)
+#define MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(E)                               \
+    ((E)->u.ptr.trg_selements[0].type)
+#define MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(E)                         \
+    (MAGIC_TYPE_IS_SPECIAL(MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(E)))
+#define MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(E,T)                       \
+    do {                                                                       \
+        (E)->u.ptr.trg_selements[0].type = T;                                  \
+        (E)->u.ptr.num_trg_types = 1;                                          \
+        (E)->u.ptr.num_legal_trg_types = 0;                                    \
+        (E)->u.ptr.first_legal_trg_type = -1;                                  \
+    } while(0)
+#define MAGIC_SEL_ANALYZED_TRG_FLAGS(E)                                        \
+    ((E)->type_id == MAGIC_TYPE_POINTER ? (E)->u.ptr.trg_flags                 \
+    : (E)->u.nonptr.trg_flags)
+#define MAGIC_SEL_ANALYZED_FLAG(E,F) (((E)->flags & F) != 0)
+#define MAGIC_SEL_ANALYZED_TRG_STATS_HAS_VIOLATIONS(E)                         \
+    ((E) == _other_types_found || (E) == _badentry_found)
+#define MAGIC_SEL_ANALYZED_TRG_STATS_C(E)                                      \
+    ((E) == _ptr_type_found ? 'p' : (E) == _other_types_found ? 'o'            \
+    : (E) == _void_type_found ? 'v' : (E) == _comp_trg_types_found ? 'c'       \
+    : (E) == _badentry_found ? 'b' : '?')
+
+#define MAGIC_SEL_ANALYZED_PRINT(E, FLAGS) do {                                \
+        _magic_printf("SEL_ANALYZED: (num=%d, type=%s, flags(DIVW)=%d%d%d%d",  \
+            (E)->num, (E)->type_id == MAGIC_TYPE_POINTER ? "ptr" : "nonptr",   \
+            MAGIC_SEL_ANALYZED_FLAG(E, MAGIC_SEL_FOUND_DATA),                  \
+            MAGIC_SEL_ANALYZED_FLAG(E, MAGIC_SEL_FOUND_INVARIANTS),            \
+            MAGIC_SEL_ANALYZED_FLAG(E, MAGIC_SEL_FOUND_VIOLATIONS),            \
+            MAGIC_SEL_ANALYZED_FLAG(E, MAGIC_SEL_FOUND_WALKABLE));             \
+        if((E)->type_id == MAGIC_TYPE_POINTER) {                               \
+            _magic_printf(", value=0x%08x, trg_name=", (E)->u.ptr.value);      \
+            MAGIC_SEL_ANALYZED_PTR_PRINT_TRG_ABS_NAME(E);                      \
+            _magic_printf(", trg_offset=%d, trg_flags(RL)=%c%c",               \
+                (E)->u.ptr.trg_offset,                                         \
+                (E)->u.ptr.trg_flags                                           \
+                    ? MAGIC_STATE_FLAGS_REGION_C((E)->u.ptr.trg_flags) : 0,    \
+                (E)->u.ptr.trg_flags                                           \
+                    ? MAGIC_STATE_FLAGS_LIBSPEC_C((E)->u.ptr.trg_flags) : 0);  \
+            if((E)->u.ptr.num_trg_types > 0) {                                 \
+                _magic_printf(", trg_selements=(");                            \
+                magic_sel_analyzed_trg_selements_print(E, FLAGS);              \
+                _magic_printf(")");                                            \
+            }                                                                  \
+        } else {                                                               \
+            _magic_printf(", value=%d/0x%08x",                                 \
+                (E)->u.nonptr.value, (E)->u.nonptr.value);                     \
+            if((E)->u.nonptr.trg_flags) {                                      \
+                _magic_printf(", trg_flags(RL)=%c%c",                          \
+                    MAGIC_STATE_FLAGS_REGION_C((E)->u.nonptr.trg_flags),       \
+                    MAGIC_STATE_FLAGS_LIBSPEC_C((E)->u.nonptr.trg_flags));     \
+            }                                                                  \
+        }                                                                      \
+        _magic_printf(")");                                                    \
+    } while(0)
+
+/* Magic state element stats. */
+struct _magic_sel_stats_s {
+    unsigned ptr_found;
+    unsigned nonptr_found;
+    unsigned nonptr_unconstrained_found;
+    int trg_flags;
+    int ptr_type_found;
+    int other_types_found;
+    int null_type_found;
+    int badoffset_found;
+    int unknown_found;
+    int void_type_found;
+    int comp_trg_types_found;
+    int value_found;
+    int badvalue_found;
+    int badentry_found;
+};
+typedef struct _magic_sel_stats_s _magic_sel_stats_t;
+
+/* Magic state element stats. */
+#define MAGIC_SEL_STAT_INCR(S,I,F) ((S)->F += (I)->F)
+#define MAGIC_SEL_STATS_INCR(S,I) do {                                         \
+        MAGIC_SEL_STAT_INCR(S,I, ptr_found);                                   \
+        MAGIC_SEL_STAT_INCR(S,I, nonptr_found);                                \
+        MAGIC_SEL_STAT_INCR(S,I, nonptr_unconstrained_found);                  \
+        S->trg_flags |= I->trg_flags;                                          \
+        MAGIC_SEL_STAT_INCR(S,I, ptr_type_found);                              \
+        MAGIC_SEL_STAT_INCR(S,I, other_types_found);                           \
+        MAGIC_SEL_STAT_INCR(S,I, null_type_found);                             \
+        MAGIC_SEL_STAT_INCR(S,I, badoffset_found);                             \
+        MAGIC_SEL_STAT_INCR(S,I, unknown_found);                               \
+        MAGIC_SEL_STAT_INCR(S,I, void_type_found);                             \
+        MAGIC_SEL_STAT_INCR(S,I, comp_trg_types_found);                        \
+        MAGIC_SEL_STAT_INCR(S,I, value_found);                                 \
+        MAGIC_SEL_STAT_INCR(S,I, badvalue_found);                              \
+        MAGIC_SEL_STAT_INCR(S,I, badentry_found);                              \
+    } while(0)
+
+#define MAGIC_SEL_STATS_HAS_VIOLATIONS(S)                                      \
+    (MAGIC_SEL_STATS_NUM_VIOLATIONS(S) > 0)
+#define MAGIC_SEL_STATS_NUM_VIOLATIONS(S)                                      \
+    ((S)->ptr_found ? MAGIC_SEL_PTR_STATS_NUM_VIOLATIONS(S)                    \
+        : MAGIC_SEL_NONPTR_STATS_NUM_VIOLATIONS(S))
+#define MAGIC_SEL_PTR_STATS_NUM_VIOLATIONS(S) ((S)->other_types_found          \
+    + (S)->badoffset_found + (S)->unknown_found + (S)->badvalue_found          \
+    + (S)->badentry_found)
+#define MAGIC_SEL_NONPTR_STATS_NUM_VIOLATIONS(S) ((S)->badvalue_found)
+
+#define MAGIC_SEL_STATS_PRINT(E) do {                                          \
+        _magic_printf("SEL_STATS: (type=%s",                                   \
+            (E)->ptr_found ? "ptr" : "nonptr");                                \
+        if((E)->trg_flags) {                                                   \
+            _magic_printf(", trg_flags(RL)=%c%c",                              \
+                MAGIC_STATE_FLAGS_REGION_C((E)->trg_flags),                    \
+                MAGIC_STATE_FLAGS_LIBSPEC_C((E)->trg_flags));                  \
+        }                                                                      \
+        if((E)->ptr_found) _magic_printf(", ptr_found=%d", (E)->ptr_found);    \
+        if((E)->nonptr_found)                                                  \
+            _magic_printf(", nonptr_found=%d", (E)->nonptr_found);             \
+        if((E)->nonptr_unconstrained_found)                                    \
+            _magic_printf(", nonptr_unconstrained_found=%d",                   \
+                (E)->nonptr_unconstrained_found);                              \
+        if((E)->ptr_type_found)                                                \
+            _magic_printf(", ptr_type_found=%d", (E)->ptr_type_found);         \
+        if((E)->other_types_found)                                             \
+            _magic_printf(", other_types_found=%d", (E)->other_types_found);   \
+        if((E)->null_type_found)                                               \
+            _magic_printf(", null_type_found=%d", (E)->null_type_found);       \
+        if((E)->badoffset_found)                                               \
+            _magic_printf(", badoffset_found=%d", (E)->badoffset_found);       \
+        if((E)->unknown_found)                                                 \
+            _magic_printf(", unknown_found=%d", (E)->unknown_found);           \
+        if((E)->void_type_found)                                               \
+            _magic_printf(", void_type_found=%d", (E)->void_type_found);       \
+        if((E)->comp_trg_types_found)                                          \
+            _magic_printf(", comp_trg_types_found=%d",                         \
+                (E)->comp_trg_types_found);                                    \
+        if((E)->value_found)                                                   \
+            _magic_printf(", value_found=%d", (E)->value_found);               \
+        if((E)->badvalue_found)                                                \
+            _magic_printf(", badvalue_found=%d", (E)->badvalue_found);         \
+        if((E)->badentry_found)                                                \
+            _magic_printf(", badentry_found=%d", (E)->badentry_found);         \
+        _magic_printf(", violations=%d", MAGIC_SEL_STATS_NUM_VIOLATIONS(E));   \
+        _magic_printf(")");                                                    \
+    } while(0)
+
+/* Magic sentry macros. */
+#define MAGIC_SENTRY_ANALYZE_STOP           1
+#define MAGIC_SENTRY_ANALYZE_CONTINUE       2
+#define MAGIC_SENTRY_ANALYZE_SKIP_PATH      3
+#define MAGIC_SENTRY_ANALYZE_IS_VALID_RET(R)                                   \
+   ((R)>=MAGIC_SENTRY_ANALYZE_STOP && (R)<=MAGIC_SENTRY_ANALYZE_SKIP_PATH)
+
+#ifndef __MINIX
+#define MAGIC_PTR_LIKELY_INTS_START         0xFFFFF000
+#else
+#define MAGIC_PTR_LIKELY_INTS_START         0xE0000000
+#endif
+#define MAGIC_PTR_LIKELY_INTS_END           0xFFF
+#define MAGIC_PTR_IS_LIKELY_INT(V)                                             \
+    ((V) && ((unsigned)(V)>=MAGIC_PTR_LIKELY_INTS_START                        \
+    || (unsigned)(V)<=MAGIC_PTR_LIKELY_INTS_END))
+#define MAGIC_INT_IS_LIKELY_PTR(V)                                             \
+    ((V) && !MAGIC_PTR_IS_LIKELY_INT((void*)V))
+
+/* Magic callbacks. */
+typedef int (*magic_cb_sentries_analyze_pre_t)();
+PUBLIC void magic_setcb_sentries_analyze_pre(magic_cb_sentries_analyze_pre_t cb);
+
+/* Magic state entry functions. */
+typedef int (*magic_sentry_analyze_cb_t)(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args);
+PUBLIC int magic_sentry_print_ptr_types(struct _magic_sentry* entry);
+PUBLIC int magic_sentry_extract_ptrs(struct _magic_sentry* entry,
+    void ****ptr_map, const struct _magic_type ***ptr_type_map, int *ptr_num);
+PUBLIC int magic_sentry_analyze(struct _magic_sentry* sentry, int flags,
+    const magic_sentry_analyze_cb_t cb, void* cb_args,
+    _magic_sel_stats_t *sentry_stats);
+PUBLIC int magic_sentries_analyze(int flags, const magic_sentry_analyze_cb_t cb,
+    void* cb_args, _magic_sel_stats_t *sentries_stats);
+PUBLIC int magic_sentry_print_selements(struct _magic_sentry* sentry);
+PUBLIC int magic_sentry_print_ptr_selements(struct _magic_sentry* sentry,
+    int skip_null_ptrs, int max_target_recusions);
+
+/* Magic dynamic state entry functions. */
+PUBLIC int magic_dsentries_analyze(int flags,
+    const magic_sentry_analyze_cb_t cb, void* cb_args,
+    _magic_sel_stats_t *dsentries_stats);
+
+/* Magic sentry analyze callbacks. */
+PUBLIC int magic_sentry_print_el_cb(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args);
+PUBLIC int magic_sentry_print_ptr_el_cb(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args);
+PUBLIC int magic_sentry_print_el_with_trg_reg_cb(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args);
+PUBLIC int magic_sentry_print_el_with_trg_cb(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args);
+
+/* Magic sentry analyze helpers. */
+#define magic_sentry_analyze_invariants(sentry, cb, cb_args, sentry_stats)     \
+    magic_sentry_analyze(sentry, MAGIC_SEL_ANALYZE_POINTERS                    \
+        | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_INVARIANTS, cb,    \
+        cb_args, sentry_stats)
+#define magic_sentries_analyze_invariants(cb, cb_args, sentries_stats)         \
+    magic_sentries_analyze(MAGIC_SEL_ANALYZE_POINTERS                          \
+        | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_INVARIANTS, cb,    \
+        cb_args, sentries_stats)
+#define magic_dsentries_analyze_invariants(cb, cb_args, dsentries_stats)       \
+    magic_dsentries_analyze(MAGIC_SEL_ANALYZE_POINTERS                         \
+        | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_INVARIANTS, cb,    \
+        cb_args, dsentries_stats)
+#define magic_allsentries_analyze_invariants(cb, cb_args, sentries_stats)      \
+    magic_sentries_analyze(MAGIC_SEL_ANALYZE_POINTERS                          \
+        | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_INVARIANTS         \
+        | MAGIC_SEL_ANALYZE_DYNAMIC, cb, cb_args, sentries_stats)
+
+#define magic_sentry_analyze_violations(sentry, cb, cb_args, sentry_stats)     \
+    magic_sentry_analyze(sentry, MAGIC_SEL_ANALYZE_POINTERS                    \
+        | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_VIOLATIONS, cb,    \
+        cb_args, sentry_stats)
+#define magic_sentries_analyze_violations(cb, cb_args, sentries_stats)         \
+    magic_sentries_analyze(MAGIC_SEL_ANALYZE_POINTERS                          \
+        | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_VIOLATIONS, cb,    \
+        cb_args, sentries_stats)
+#define magic_dsentries_analyze_violations(cb, cb_args, dsentries_stats)       \
+    magic_dsentries_analyze(MAGIC_SEL_ANALYZE_POINTERS                         \
+        | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_VIOLATIONS, cb,    \
+        cb_args, dsentries_stats)
+#define magic_allsentries_analyze_violations(cb, cb_args, sentries_stats)      \
+    magic_sentries_analyze(MAGIC_SEL_ANALYZE_POINTERS                          \
+        | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_VIOLATIONS         \
+        | MAGIC_SEL_ANALYZE_DYNAMIC, cb, cb_args, sentries_stats)
+
+#define magic_sentry_analyze_likely_pointers(sentry, cb, cb_args, sentry_stats)\
+    magic_sentry_analyze(sentry, MAGIC_SEL_ANALYZE_LIKELYPOINTERS              \
+        | MAGIC_SEL_ANALYZE_DATA, cb, cb_args, sentry_stats)
+#define magic_sentries_analyze_likely_pointers(cb, cb_args, sentries_stats)    \
+    magic_sentries_analyze(MAGIC_SEL_ANALYZE_LIKELYPOINTERS                    \
+        | MAGIC_SEL_ANALYZE_DATA, cb, cb_args, sentries_stats)
+#define magic_dsentries_analyze_likely_pointers(cb, cb_args, dsentries_stats)  \
+    magic_dsentries_analyze(MAGIC_SEL_ANALYZE_LIKELYPOINTERS                   \
+        | MAGIC_SEL_ANALYZE_DATA, cb, cb_args, dsentries_stats)
+#define magic_allsentries_analyze_likely_pointers(cb, cb_args, sentries_stats) \
+    magic_sentries_analyze(MAGIC_SEL_ANALYZE_LIKELYPOINTERS                    \
+        | MAGIC_SEL_ANALYZE_DATA | MAGIC_SEL_ANALYZE_DYNAMIC, cb, cb_args,     \
+        sentries_stats)
+
+/* Magic state type functions. */
+PUBLIC int magic_type_count_ptrs(const struct _magic_type* type, int *ptr_num);
+
+/* Magic type walk callbacks. */
+PUBLIC int magic_type_examine_ptr_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num, const struct _magic_type* type,
+    const unsigned offset, int depth, void* cb_args);
+PUBLIC int magic_type_extract_ptr_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num, const struct _magic_type* type,
+    const unsigned offset, int depth, void* cb_args);
+PUBLIC int magic_type_analyzer_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num, const struct _magic_type* type,
+    const unsigned offset, int depth, void* cb_args);
+
+/* Magic state element functions. */
+PUBLIC int magic_selement_analyze(_magic_selement_t *selement, int flags,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats);
+PUBLIC int magic_selement_analyze_ptr(_magic_selement_t *selement, int flags,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats);
+PUBLIC int magic_selement_analyze_nonptr(_magic_selement_t *selement, int flags,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats);
+PUBLIC int magic_selement_analyze_ptr_value_invs(_magic_selement_t *selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats);
+PUBLIC int magic_selement_analyze_ptr_trg_invs(_magic_selement_t *selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats);
+PUBLIC _magic_trg_stats_t
+magic_selement_analyze_ptr_target(const struct _magic_type *ptr_type,
+    const struct _magic_type *trg_type, int trg_flags);
+PUBLIC int magic_selement_analyze_ptr_type_invs(_magic_selement_t *selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats);
+PUBLIC int magic_selement_recurse_ptr(_magic_selement_t *selement,
+    _magic_selement_t *new_selement, int max_steps);
+PUBLIC void
+magic_sel_analyzed_trg_selements_print(_magic_sel_analyzed_t *sel_analyzed,
+    int flags);
+PUBLIC _magic_selement_t*
+magic_selement_type_cast(_magic_selement_t *selement, int flags,
+    const struct _magic_type* type, _magic_sel_analyzed_t *sel_analyzed,
+    _magic_sel_stats_t *sel_stats);
+
+#endif /* _MAGIC_ANALYSIS_H */
+
diff --git a/minix/llvm/include/magic_asr.h b/minix/llvm/include/magic_asr.h
new file mode 100644 (file)
index 0000000..5cecde2
--- /dev/null
@@ -0,0 +1,11 @@
+#include <magic_def.h>
+#include <magic.h>
+#include <magic_mem.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+PUBLIC int magic_asr_get_padding_size(int region);
+PUBLIC void magic_asr_permute_dsentries(struct _magic_dsentry
+    **first_dsentry_ptr);
+PUBLIC void magic_asr_init();
diff --git a/minix/llvm/include/magic_def.h b/minix/llvm/include/magic_def.h
new file mode 100644 (file)
index 0000000..67276cc
--- /dev/null
@@ -0,0 +1,188 @@
+#ifndef _MAGIC_DEF_H
+#define _MAGIC_DEF_H
+
+#if defined(_MINIX) || defined(_MINIX_SYSTEM)
+#ifndef __MINIX
+#define __MINIX 1
+#endif
+#endif
+
+#include <limits.h>
+
+/* Type macros. */
+#ifdef __MINIX
+#define MAGIC_LONG_LONG_SUPPORTED     1
+#define MAGIC_LONG_DOUBLE_SUPPORTED   0
+#else
+#ifdef LLONG_MAX
+#define MAGIC_LONG_LONG_SUPPORTED     1
+#endif
+#ifdef __LDBL_MAX__
+#define MAGIC_LONG_DOUBLE_SUPPORTED   1
+#endif
+#endif
+
+/* Modifier macros. */
+#define EXTERN  extern
+#define PRIVATE static
+#ifdef __SHARED__
+#define PUBLIC EXTERN
+#else
+#define PUBLIC
+#endif
+
+#ifdef __MINIX
+#define INLINE __inline__
+#define THREAD_LOCAL
+#undef UNUSED
+#define FUNCTION_BLOCK(B) B
+#else
+#define INLINE inline
+#define THREAD_LOCAL __thread
+#ifdef __cplusplus
+#define FUNCTION_BLOCK(B) extern "C"{ B }
+#else
+#define FUNCTION_BLOCK(B) B
+#endif
+#endif
+
+#define UNUSED(VAR) VAR __attribute__((unused))
+#define USED __attribute__((used))
+#define VOLATILE volatile
+
+/* Magic macros. */
+#define MAGIC_VAR USED
+#define MAGIC_FUNC PUBLIC USED __attribute__((noinline))
+#define MAGIC_FUNC_BODY() __asm__("")
+#define MAGIC_HOOK PUBLIC USED __attribute__((always_inline)) inline
+#define MAGIC_MACRO_FUNC __attribute__((always_inline))
+
+#define TRUE  1
+#define FALSE 0
+
+#ifdef __MINIX
+#define SYS_PAGESIZE 4096
+#else
+#define SYS_PAGESIZE sysconf(_SC_PAGESIZE)
+#endif
+#define MAGIC_ROUND_DOWN(val, round)        ((val) & ~((round) - 1))
+#define MAGIC_ROUND_UP(val, round)           (MAGIC_ROUND_DOWN(val, round) ==  \
+    (val) ? (val) : MAGIC_ROUND_DOWN((val) + (round), (round)))
+#define MAGIC_ROUND_DOWN_TO_PAGESIZE(addr)  MAGIC_ROUND_DOWN(addr, SYS_PAGESIZE)
+#define MAGIC_ROUND_UP_TO_PAGESIZE(addr)    MAGIC_ROUND_UP(addr, SYS_PAGESIZE)
+
+#ifdef __MINIX
+#define _MAGIC_CAS(P, O, N) (*(P) == (O) ? *(P)=(N) : (N)+1)
+#define MAGIC_CAS(P, O, N)  (_MAGIC_CAS(P, O, N) == (N) ? (O) : *(P))
+#define MAGIC_FAA(P, V) (((*P)+=V)-V)
+#define MAGIC_FAS(P, V) (((*P)-=V)+V)
+#else
+#define MAGIC_CAS(P, O, N) __sync_val_compare_and_swap((P), (O), (N))
+#define MAGIC_FAA(P, V) __sync_fetch_and_add(P, V)
+#define MAGIC_FAS(P, V) __sync_fetch_and_sub(P, V)
+#endif
+
+/* Magic arch-specific macros. */
+#define MAGIC_FRAMEADDR_TO_RETADDR_PTR(F) (((char*)(F))+4)
+
+/* Magic ranges. */
+#define MAGIC_LINKER_VAR_NAMES   "end", "etext", "edata", NULL
+
+#ifdef __MINIX
+#define MAGIC_TEXT_START         ((void*)(0x1000))
+#define MAGIC_STACK_GAP          (4*1024)
+#else
+#define MAGIC_TEXT_START         ((void*)(0x08048000))
+#define MAGIC_STACK_GAP          (4*1024*1024)
+#endif
+
+#define MAGIC_TEXT_END           0    /* 0 if right before data. */
+#define MAGIC_HEAP_START         0    /* 0 if right after data.  */
+#define MAGIC_HEAP_GAP           (4*1024)
+#define MAGIC_RANGE_ROUND_DATA   1
+#define MAGIC_RANGE_ROUND_TEXT   1
+#define MAGIC_RANGE_ROUND_STACK  1
+
+/* Magic IDs */
+#define MAGIC_ID_NONE 0
+#define MAGIC_ID_FORCE_LONG 1
+#if defined(__MINIX) || MAGIC_ID_FORCE_LONG
+typedef unsigned long _magic_id_t;
+#define MAGIC_ID_MAX    ULONG_MAX
+#define MAGIC_ID_FORMAT "%lu"
+#else
+typedef unsigned long long _magic_id_t;
+#define MAGIC_ID_MAX ULLONG_MAX
+#define MAGIC_ID_FORMAT "%llu"
+#endif
+
+/* Magic error codes. */
+#define MAGIC_ENOENT      (-100)
+#define MAGIC_EBADENT     (-101)
+#define MAGIC_EBADMSTATE  (-102)
+#define MAGIC_EINVAL      (-103)
+#define MAGIC_EGENERIC    (-104)
+#define MAGIC_EBADWALK    (-105)
+#define MAGIC_ERANGE      (-106)
+#define MAGIC_ESIGN       (-107)
+#define MAGIC_ENOMEM      (-108)
+#define MAGIC_ENOPTR      ((void*)-1)
+
+/*
+ * Basic return type definitions. Not really needed, but they make
+ * the code easier to read.
+ */
+#ifndef OK
+#define OK                                  0
+#endif
+#ifndef EGENERIC
+#define EGENERIC                            -1
+#endif
+
+/* Magic printf. */
+#ifdef __MINIX
+#define MAGIC_PRINTF_DEFAULT printf
+#else
+#define MAGIC_PRINTF_DEFAULT magic_err_printf
+#endif
+
+FUNCTION_BLOCK(
+
+typedef int (*printf_ptr_t) (char const *str, ...);
+EXTERN printf_ptr_t _magic_printf;
+EXTERN void magic_assert_failed(const char *assertion, const char *file,
+    const char *function, const int line);
+
+)
+
+/* assert() override. */
+#define ENABLE_ASSERTIONS 1
+#ifndef __MINIX
+#define CUSTOM_ASSERTIONS 0
+#else
+#define CUSTOM_ASSERTIONS 1
+#endif
+
+#include <assert.h>
+
+#if CUSTOM_ASSERTIONS
+#ifdef assert
+#undef assert
+#endif
+#ifndef __ASSERT_FUNCTION
+#define __ASSERT_FUNCTION ""
+#endif
+
+#if ENABLE_ASSERTIONS
+#define assert(X) do{       \
+        if(!(X)) {          \
+            magic_assert_failed(#X, __FILE__, __ASSERT_FUNCTION, __LINE__); \
+        }                   \
+    } while(0)
+#else
+#  define assert(X)
+#endif
+#endif
+
+#endif
+
diff --git a/minix/llvm/include/magic_eval.h b/minix/llvm/include/magic_eval.h
new file mode 100644 (file)
index 0000000..7dd598e
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _MAGIC_EVAL_H
+#define _MAGIC_EVAL_H
+
+#include <magic_def.h>
+
+typedef long (*magic_eval_func_t) (long arg);
+
+PUBLIC void magic_eval_init();
+
+/* Eval frontends. */
+PUBLIC int magic_eval_int(char *expr, long *result);
+PUBLIC int magic_eval_bool(char *expr, char *result);
+PUBLIC int magic_eval_float(char *expr, double *result);
+
+/* Printing. */
+#define MAGIC_EVAL_PRINT_FUNC_RESULTS   0x01
+#define MAGIC_EVAL_PRINT_VAR_VALUES     0x02
+#define MAGIC_EVAL_PRINT_STYLE_DEFAULT  0
+#define MAGIC_EVAL_PRINT_STYLE_ALL      (MAGIC_EVAL_PRINT_FUNC_RESULTS|MAGIC_EVAL_PRINT_VAR_VALUES)
+
+PUBLIC int magic_eval_get_print_style(void);
+PUBLIC void magic_eval_set_print_style(int style);
+
+#endif
+
diff --git a/minix/llvm/include/magic_eval_lib.h b/minix/llvm/include/magic_eval_lib.h
new file mode 100644 (file)
index 0000000..8b0bb25
--- /dev/null
@@ -0,0 +1,74 @@
+/* evaluate.h (C) 2000-2002 Kyzer/CSG. */
+/* Released under the terms of the GNU General Public Licence version 2. */
+/* http://www.kyzer.me.uk/code/evaluate/ */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#define T_INT    0
+#define T_REAL   1
+
+/* value */
+struct val {
+  long   ival; /* if type = T_INT, this is the result */
+  double rval; /* if type = T_REAL, this is the result */
+  char   type; /* either T_INT or T_REAL */
+};
+
+/* variable */
+struct var {
+  struct var *next; /* next variable in table or NULL */
+  struct val val;   /* value of variable */
+  char   *name;     /* name of variable */
+};
+
+/* variable table */
+struct vartable {
+  struct var *first; /* first entry in variable table */
+  struct memh *mh;
+};
+
+/* creates a new variable table (NULL if no memory) */
+struct vartable *create_vartable();
+
+/* frees a variable table */
+void free_vartable(struct vartable *vt);
+
+/* gets a variable from a variable table (NULL if not found) */
+struct var *get_var(struct vartable *vt, char *name);
+
+/* puts a variable into a variable table (NULL if no memory) */
+struct var *put_var(struct vartable *vt, char *name, struct val *value);
+
+/* callbacks */
+typedef struct val*(*get_var_cb_t)(char*, struct val*);
+typedef struct val*(*get_func_result_cb_t)(char*, struct val*, struct val*);
+void eval_set_cb_get_var(get_var_cb_t cb);
+void eval_set_cb_get_func_result(get_func_result_cb_t cb);
+
+/* THE FUNCTION YOU WANT TO CALL */
+
+/* given a string to evaluate (not NULL), a result to put the answer in
+ * (not NULL) and optionally your own variable table (NULL for 'internal
+ * only' vartable), will return an error code (and result, etc)
+ */
+int evaluate(char *eval, struct val *result, struct vartable *variables);
+
+/* errors */
+#define RESULT_OK               0       /* all OK                       */
+#define ERROR_SYNTAX            2       /* invalid expression           */
+#define ERROR_VARNOTFOUND       3       /* variable not found           */
+#define ERROR_FUNCNOTFOUND      4       /* function not found           */
+#define ERROR_NOMEM             8       /* not enough memory available  */
+#define ERROR_DIV0              9       /* division by zero             */
+#define ERROR_BUSY             10       /* busy now                     */
+
+/* configuration */
+#define TOKEN_DEBUG             0
+#define EVAL_DEBUG              0
+#define EVAL_MALLOC             0
+#define USE_MATH_LIB            0
+#define MEM_DEBUG               0
+#define MEM_LOW_FOOTPRINT       1
+#define VAR_FROM_ENV            0
+
diff --git a/minix/llvm/include/magic_mem.h b/minix/llvm/include/magic_mem.h
new file mode 100644 (file)
index 0000000..63fb030
--- /dev/null
@@ -0,0 +1,284 @@
+#ifndef _MAGIC_MEM_H
+#define _MAGIC_MEM_H
+
+#include <magic.h>
+
+#define __MA_ARGS__             struct _magic_type *type, char *name, char *parent_name,
+#define __MA_VALUES__           type, name, parent_name,
+#define __MA_VALUES_EXT__       MAGIC_VOID_TYPE, MAGIC_ALLOC_EXT_NAME, MAGIC_ALLOC_EXT_PARENT_NAME,
+
+#define __MD_ARGS__
+#define __MD_VALUES__
+#define __MD_VALUES_EXT__
+#define __MD_VALUES_DEFAULT__
+
+/* External callbacks. */
+typedef void *(*magic_mem_heap_alloc_cb_t)(size_t size, char *name, char *parent_name);
+typedef void (*magic_mem_create_dsentry_cb_t)(struct _magic_dsentry *dsentry);
+typedef int (*magic_mem_heap_free_cb_t)(struct _magic_dsentry *dsentry);
+extern magic_mem_heap_alloc_cb_t magic_mem_heap_alloc_cb;
+extern magic_mem_create_dsentry_cb_t magic_mem_create_dsentry_cb;
+extern magic_mem_heap_free_cb_t magic_mem_heap_free_cb;
+
+/* Public dsentry functions. */
+typedef void (*magic_dsentry_cb_t)(struct _magic_dsentry*);
+PUBLIC int magic_create_dsentry(struct _magic_dsentry *dsentry,
+    void *data_ptr, struct _magic_type *type, size_t size, int flags,
+    char *name, char *parent_name);
+PUBLIC struct _magic_obdsentry* magic_create_obdsentry(void *data_ptr,
+    struct _magic_type *type, size_t size, int flags,
+    char *name, char *parent_name);
+PUBLIC int magic_update_dsentry_state(struct _magic_dsentry *dsentry,
+    unsigned long mstate);
+PUBLIC void magic_free_dead_dsentries();
+PUBLIC void magic_destroy_dsentry(struct _magic_dsentry *dsentry,
+    struct _magic_dsentry *prev_dsentry);
+PUBLIC void magic_destroy_dsentry_set_ext_cb(const magic_dsentry_cb_t cb);
+PUBLIC int magic_destroy_obdsentry_by_addr(void *data_ptr);
+PUBLIC int magic_update_dsentry(void* addr, struct _magic_type *type);
+PUBLIC void magic_stack_dsentries_create(
+    struct _magic_dsentry **prev_last_stack_dsentry, int num_dsentries,
+    /* struct _magic_dsentry *dsentry, struct _magic_type *type, void* data_ptr, char* function_name, char* name, */ ...);
+PUBLIC void magic_stack_dsentries_destroy(
+    struct _magic_dsentry **prev_last_stack_dsentry, int num_dsentries,
+    /* struct _magic_dsentry *dsentry, */ ...);
+
+/* Public dfunction functions. */
+PUBLIC int magic_create_dfunction(struct _magic_dfunction *dfunction,
+    void *data_ptr, struct _magic_type *type, int flags,
+    char *name, char *parent_name);
+PUBLIC void magic_destroy_dfunction(struct _magic_dfunction *dfunction);
+
+/* Public sodesc functions. */
+PUBLIC int magic_create_sodesc(struct _magic_sodesc *sodesc);
+PUBLIC int magic_destroy_sodesc(struct _magic_sodesc *sodesc);
+
+/* Public dsodesc functions. */
+PUBLIC int magic_create_dsodesc(struct _magic_dsodesc *dsodesc);
+PUBLIC int magic_destroy_dsodesc(struct _magic_dsodesc *dsodesc);
+
+/* Memory usage logging support. */
+#if MAGIC_MEM_USAGE_OUTPUT_CTL
+/* CPU frequency (used for timestamp generation) */
+EXTERN double magic_cycles_per_ns;
+#endif
+
+/* Magic malloc wrappers. */
+#include <stdlib.h>
+#ifndef __MINIX
+#include <malloc.h>
+#endif
+
+PUBLIC void *magic_alloc(__MA_ARGS__ void *ptr, size_t size, int flags);
+PUBLIC void *magic_malloc( __MA_ARGS__ size_t size);
+PUBLIC void *magic_calloc( __MA_ARGS__ size_t nmemb, size_t size);
+PUBLIC void  magic_free(   __MD_ARGS__ void *ptr);
+PUBLIC void *magic_realloc(__MA_ARGS__ void *ptr, size_t size);
+
+PUBLIC void *(*magic_real_malloc)(size_t size);
+PUBLIC void *(*magic_real_calloc)(size_t nmemb, size_t size);
+PUBLIC void  (*magic_real_free)(void *ptr);
+PUBLIC void *(*magic_real_realloc)(void *ptr, size_t size);
+
+PUBLIC int magic_posix_memalign(__MA_ARGS__ void **memptr, size_t alignment, size_t size);
+PUBLIC int (*magic_real_posix_memalign)(void **memptr, size_t alignment, size_t size);
+
+#ifndef __MINIX
+PUBLIC void *magic_valloc(      __MA_ARGS__ size_t size);
+PUBLIC void *magic_memalign(    __MA_ARGS__ size_t boundary, size_t size);
+
+PUBLIC void *(*magic_real_valloc)(size_t size);
+PUBLIC void *(*magic_real_memalign)(size_t boundary, size_t size);
+#endif
+
+/* Magic mmap wrappers. */
+#include <sys/mman.h>
+
+#ifdef __MINIX
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+#endif
+
+#ifndef _GNU_SOURCE
+void *mmap64(void *addr, size_t length, int prot, int flags, int fd, off_t pgoffset);
+#endif
+
+PUBLIC void *magic_mmap(__MA_ARGS__ void *start, size_t length, int prot, int flags,
+    int fd, off_t offset);
+PUBLIC int magic_munmap(__MD_ARGS__ void *start, size_t length);
+
+PUBLIC void *(*magic_real_mmap)(void *start, size_t length, int prot, int flags,
+    int fd, off_t offset);
+PUBLIC int (*magic_real_munmap)(void *start, size_t length);
+
+/* Magic brk wrappers. */
+#include <unistd.h>
+
+PUBLIC int magic_brk(   __MA_ARGS__ void *addr);
+PUBLIC void *magic_sbrk(__MA_ARGS__ intptr_t increment);
+
+PUBLIC int (*magic_real_brk)(void *addr);
+PUBLIC void *(*magic_real_sbrk)(intptr_t increment);
+
+#ifndef __MINIX
+/* Magic shm wrappers. */
+#include <sys/types.h>
+#include <sys/shm.h>
+
+PUBLIC void *magic_shmat(__MA_ARGS__ int shmid, const void *shmaddr, int shmflg);
+PUBLIC int magic_shmdt(  __MD_ARGS__ const void *shmaddr);
+
+PUBLIC void *(*magic_real_shmat)(int shmid, const void *shmaddr, int shmflg);
+PUBLIC int (*magic_real_shmdt)(const void *shmaddr);
+
+/* Magic other wrappers. */
+PUBLIC void *magic_mmap64(__MA_ARGS__ void *start, size_t length, int prot, int flags,
+    int fd, off_t pgoffset);
+
+PUBLIC void *(*magic_real_mmap64)(void *start, size_t length, int prot, int flags,
+    int fd, off_t pgoffset);
+#else
+#include <minix/vm.h>
+
+PUBLIC void *magic_vm_map_cacheblock(__MA_ARGS__ dev_t dev, off_t dev_offset,
+    ino_t ino, off_t ino_offset, u32_t *flags, int blocksize);
+PUBLIC void *(*magic_real_vm_map_cacheblock)(dev_t dev, off_t dev_offset,
+    ino_t ino, off_t ino_offset, u32_t *flags, int blocksize);
+#endif
+
+/* wrappers to skip alloction */
+PUBLIC void *magic_malloc_positioned( __MA_ARGS__ size_t size, void *ptr);
+PUBLIC void *magic_mmap_positioned(__MA_ARGS__ void *start, size_t length, int prot, int flags,
+    int fd, off_t offset, struct _magic_dsentry *cached_dsentry);
+
+/* Macros. */
+#define MAGIC_ALLOC_SIZE                    (sizeof(struct _magic_dsentry))
+
+#define MAGIC_SIZE_TO_REAL(S)               (S + MAGIC_ALLOC_SIZE)
+#define MAGIC_SIZE_TO_SOURCE(S)             (S - MAGIC_ALLOC_SIZE)
+#define MAGIC_PTR_TO_DSENTRY(P)                                                \
+    ((struct _magic_dsentry *) (((char *)P)))
+#define MAGIC_PTR_FROM_DSENTRY(P)           ((void *) P)
+#define MAGIC_PTR_TO_DATA(P)                                                   \
+    ((void *) (((char *)P) + MAGIC_ALLOC_SIZE))
+#define MAGIC_PTR_FROM_DATA(P)                                                 \
+    ((void *) (((char *)P) - MAGIC_ALLOC_SIZE))
+
+/* Variables to keep track of magic mem wrappers. */
+EXTERN THREAD_LOCAL short magic_mem_wrapper_active;
+EXTERN short magic_mem_create_dsentry_site_id;
+
+/* Variables to indicate if dsentry site_ids should be created. */
+
+#if MAGIC_ALLOW_DYN_MEM_WRAPPER_NESTING
+#define MAGIC_MEM_WRAPPER_IS_ACTIVE()   (magic_mem_wrapper_active > 0)
+#define MAGIC_MEM_WRAPPER_BEGIN()       do {                                   \
+        magic_mem_wrapper_active++;                                            \
+    } while(0)
+#define MAGIC_MEM_WRAPPER_END()         do {                                   \
+        assert(MAGIC_MEM_WRAPPER_IS_ACTIVE());                                 \
+        magic_mem_wrapper_active--;                                            \
+    } while(0)
+#else
+#define MAGIC_MEM_WRAPPER_IS_ACTIVE()   (magic_mem_wrapper_active == 1)
+#define MAGIC_MEM_WRAPPER_BEGIN()       do {                                   \
+        assert(!MAGIC_MEM_WRAPPER_IS_ACTIVE());                                \
+        magic_mem_wrapper_active = 1;                                          \
+    } while(0)
+#define MAGIC_MEM_WRAPPER_END()         do {                                   \
+        assert(MAGIC_MEM_WRAPPER_IS_ACTIVE());                                 \
+        magic_mem_wrapper_active = 0;                                          \
+    } while(0)
+#endif
+
+#define MAGIC_MEM_WRAPPER_LBEGIN()       do {                                  \
+        MAGIC_MEM_WRAPPER_BEGIN();                                             \
+        MAGIC_DSENTRY_LOCK();                                                  \
+    } while(0)
+#define MAGIC_MEM_WRAPPER_LEND()         do {                                  \
+        MAGIC_MEM_WRAPPER_END();                                               \
+        MAGIC_DSENTRY_UNLOCK();                                                \
+    } while(0)
+#define MAGIC_MEM_WRAPPER_BLOCK(BLOCK)   do {                                  \
+        MAGIC_MEM_WRAPPER_BEGIN();                                             \
+        BLOCK                                                                  \
+        MAGIC_MEM_WRAPPER_END();                                               \
+    } while(0)
+#define MAGIC_MEM_WRAPPER_LBLOCK(BLOCK)  do {                                  \
+        MAGIC_MEM_WRAPPER_LBEGIN();                                            \
+        BLOCK                                                                  \
+        MAGIC_MEM_WRAPPER_LEND();                                              \
+    } while(0)
+
+/* Variables to keep track of memory pool management functions. */
+#define MAGIC_MEMPOOL_ID_UNKNOWN            -1
+#define MAGIC_MEMPOOL_ID_DETACHED           -2
+#define MAGIC_MEMPOOL_MAX_FUNC_RECURSIONS   100
+EXTERN THREAD_LOCAL short magic_mempool_mgmt_active_level;
+EXTERN THREAD_LOCAL short magic_mempool_ids[MAGIC_MEMPOOL_MAX_FUNC_RECURSIONS];
+EXTERN int magic_mempool_allow_reset;
+EXTERN int magic_mempool_allow_reuse;
+
+/* TLS flags to be set when pool management functions are active. */
+#define MAGIC_MEMPOOL_MGMT_SET_ACTIVE()                                        \
+    assert((++magic_mempool_mgmt_active_level <= MAGIC_MEMPOOL_MAX_FUNC_RECURSIONS) \
+            && "Reached the maximum number of nested pool function calls!")
+#define MAGIC_MEMPOOL_MGMT_IS_ACTIVE()                                         \
+    (magic_mempool_mgmt_active_level > 0)
+#define MAGIC_MEMPOOL_MGMT_UNSET_ACTIVE()                                      \
+    assert((--magic_mempool_mgmt_active_level >= 0) && "Invalid nested pool call level!")
+#define MAGIC_MEMPOOL_SET_ID(ID)                                               \
+    (magic_mempool_ids[magic_mempool_mgmt_active_level - 1] = ID)
+#define MAGIC_MEMPOOL_GET_ID()                                                 \
+    (magic_mempool_ids[magic_mempool_mgmt_active_level - 1])
+#define MAGIC_MEMPOOL_ID_IS_SET()                                              \
+    (magic_mempool_ids[magic_mempool_mgmt_active_level - 1] > 0)
+#define MAGIC_MEMPOOL_GET_NAME()                                               \
+    (MAGIC_MEMPOOL_ID_IS_SET() ?                                               \
+        _magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1].name :                      \
+        ((MAGIC_MEMPOOL_GET_ID() == MAGIC_MEMPOOL_ID_UNKNOWN) ?                \
+            MAGIC_MEMPOOL_NAME_UNKNOWN : MAGIC_MEMPOOL_NAME_DETACHED))
+/*  Store dynamic type in TLS if memory usage logging is enabled */
+#if MAGIC_MEM_USAGE_OUTPUT_CTL
+#define        MAGIC_MEMPOOL_SET_DTYPE(TYPE)                                          \
+    do {                                                                       \
+        if (MAGIC_MEMPOOL_ID_IS_SET())  {                                      \
+            _magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1].dtype_id = TYPE;        \
+        }                                                                      \
+    } while(0)
+#define        MAGIC_MEMPOOL_GET_DTYPE()                                              \
+    (MAGIC_MEMPOOL_ID_IS_SET() ?                                               \
+            _magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1].dtype_id : 0)
+#else
+#define        MAGIC_MEMPOOL_SET_DTYPE(TYPE)
+#define        MAGIC_MEMPOOL_GET_DTYPE()   0
+#endif
+
+/* Pass call site information when logging is activated. */
+#if (MAGIC_MEM_USAGE_OUTPUT_CTL == 1)
+#define __MDEBUG_ARGS__             char* name
+#else
+#define __MDEBUG_ARGS__
+#endif
+/* Specific wrapper for the memory pool creation. */
+MAGIC_HOOK void magic_mempool_create_begin(__MDEBUG_ARGS__);
+MAGIC_HOOK void magic_mempool_create_end(void* addr, int indirection);
+
+/* Specific wrappers for the memory pool destruction. */
+MAGIC_HOOK void magic_mempool_destroy_begin(void* addr, int memory_reuse);
+MAGIC_HOOK void magic_mempool_destroy_end();
+
+/* Specific wrappers for the memory pool resetting */
+MAGIC_HOOK void magic_mempool_reset_begin(void* addr);
+
+/* Generic wrappers for the rest of the memory pool management functions. */
+MAGIC_HOOK void magic_mempool_mgmt_begin(void* addr);
+MAGIC_HOOK void magic_mempool_mgmt_end();
+
+/* Pool block allocation template function and magic wrapper. */
+MAGIC_FUNC void *mempool_block_alloc_template(void* addr, size_t size);
+PUBLIC void *magic_mempool_block_alloc_template(__MA_ARGS__ void* addr, size_t size);
+
+#endif
+
diff --git a/minix/llvm/include/magic_range.h b/minix/llvm/include/magic_range.h
new file mode 100644 (file)
index 0000000..ce3a0ba
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef _MAGIC_RANGE_H
+#define _MAGIC_RANGE_H
+
+#include <magic.h>
+#include <magic_def.h>
+#include <magic_common.h>
+#include <magic_structs.h>
+
+/* Magic memory ranges */
+#define magic_null_range              _magic_vars->null_range
+#define magic_data_range              _magic_vars->data_range
+#define magic_heap_range              _magic_vars->heap_range
+#define magic_map_range               _magic_vars->map_range
+#define magic_shm_range               _magic_vars->shm_range
+#define magic_stack_range             _magic_vars->stack_range
+#define magic_text_range              _magic_vars->text_range
+
+#define magic_sentry_range            _magic_vars->sentry_range
+#define magic_function_range          _magic_vars->function_range
+#define magic_dfunction_range         _magic_vars->dfunction_range
+
+#define magic_heap_start              _magic_vars->heap_start
+#define magic_heap_end                _magic_vars->heap_end
+#define magic_update_dsentry_ranges   _magic_vars->update_dsentry_ranges
+#define magic_update_dfunction_ranges _magic_vars->update_dfunction_ranges
+
+/* Magic address ranges. */
+#define MAGIC_ADDR_IS_WITHIN(A, MIN, MAX)   ((MIN) <= (A) && (A) <= (MAX))
+#define MAGIC_ADDR_IS_IN_RANGE(A, R)                                           \
+    MAGIC_ADDR_IS_WITHIN(A, (R)[0], (R)[1])
+#define MAGIC_RANGE_IS_IN_RANGE(r, R)                                          \
+    (MAGIC_ADDR_IS_IN_RANGE((r)[0], R) && MAGIC_ADDR_IS_IN_RANGE((r)[1], R))
+#define MAGIC_RANGE_COPY(RS, RD)            memcpy(RD, RS, 2 * sizeof(void *))
+#define MAGIC_RANGE_INIT(R)                 MAGIC_RANGE_COPY(magic_null_range,R)
+#define MAGIC_RANGE_IS_NULL(R)                                                 \
+    ((R)[0] == magic_null_range[0] && (R)[1] == magic_null_range[1])
+#define MAGIC_RANGE_IS_VALID(R)                                                \
+    (MAGIC_RANGE_IS_NULL(R) || ((R)[0] <= (R)[1]))
+#define MAGIC_RANGE_UPDATE(R, MIN, MAX)                                        \
+    do {                                                                       \
+        if(MIN < (R)[0])                                                       \
+            (R)[0] = MIN;                                                      \
+        if(MAX > (R)[1])                                                       \
+            (R)[1] = MAX;                                                      \
+    } while(0)
+#define MAGIC_RANGE_SET_MIN(R, MIN)         ((R)[0] = MIN)
+#define MAGIC_RANGE_SET_MAX(R, MAX)         ((R)[1] = MAX)
+#define MAGIC_RANGE_SET(R, MIN, MAX)                                           \
+    do {                                                                       \
+        MAGIC_RANGE_SET_MIN(R, MIN);                                           \
+        MAGIC_RANGE_SET_MAX(R, MAX);                                           \
+    } while(0)
+#define MAGIC_RANGE_PAGE_ROUND_MIN(R)                                          \
+    ((R)[0] = (char*)(R)[0] - (unsigned long)(R)[0] % MAGIC_PAGE_SIZE)
+#define MAGIC_RANGE_PAGE_ROUND_MAX(R)                                          \
+    do {                                                                       \
+        unsigned long diff = (unsigned long)(R)[1] % MAGIC_PAGE_SIZE;          \
+        if(diff)                                                               \
+            (R)[1] = (char *)(R)[1] + MAGIC_PAGE_SIZE - diff - 1;              \
+    } while(0)
+#define MAGIC_RANGE_PAGE_ROUND(R)                                              \
+    do {                                                                       \
+        MAGIC_RANGE_PAGE_ROUND_MIN(R);                                         \
+        MAGIC_RANGE_PAGE_ROUND_MAX(R);                                         \
+    } while(0)
+#define MAGIC_RANGE_PRINT(R)                                                   \
+    _magic_printf("RANGE %s=[0x%08x;0x%08x]", #R, (unsigned long)((R)[0]),     \
+        (unsigned long)((R)[1]))
+#define MAGIC_RANGE_CHECK(R)                                                   \
+    assert(MAGIC_RANGE_IS_VALID(R) && "Invalid range " #R);
+#define MAGIC_RANGE_SIZE(R)                                                    \
+    (!MAGIC_RANGE_IS_VALID(R) || MAGIC_RANGE_IS_NULL(R) ?                      \
+        0 : (char *)(R)[1] - (char *)(R)[0])
+
+#if MAGIC_RANGE_DEBUG
+#define MAGIC_RANGE_DEBUG_ADDR(A, R)                                           \
+    do {                                                                       \
+        char *what = MAGIC_ADDR_IS_IN_RANGE(A, R) ? "" : "not ";               \
+        _magic_printf("MRD: Address 0x%08x %sin ", A, what);                   \
+        MAGIC_RANGE_PRINT(R);                                                  \
+        _magic_printf("\n");                                                   \
+        MAGIC_RANGE_CHECK(R);                                                  \
+    } while(0);
+#else
+#define MAGIC_RANGE_DEBUG_ADDR(A,R)         MAGIC_RANGE_CHECK(R)
+#endif
+
+#define MAGIC_ADDR_LOOKUP_USE_DSENTRY_RANGES      1
+#define MAGIC_ADDR_LOOKUP_USE_DFUNCTION_RANGES    1
+
+/* Magic range functions. */
+PUBLIC void magic_ranges_init(void);
+PUBLIC int magic_range_is_dfunction(void* addr);
+PUBLIC int magic_range_is_dsentry(void* addr);
+PUBLIC int magic_range_is_stack(void* addr);
+
+/* Lookup functions. */
+PUBLIC int magic_range_lookup_by_addr(void *addr, void **container);
+
+#endif /* _MAGIC_RANGE_H */
diff --git a/minix/llvm/include/magic_rcu.h b/minix/llvm/include/magic_rcu.h
new file mode 100644 (file)
index 0000000..76c3902
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _MAGIC_RCU_H
+#define _MAGIC_RCU_H
+
+void magic_rcu_quiescent_begin();
+void magic_rcu_quiescent_end();
+void magic_rcu_quiescent_state();
+void magic_rcu_quiescent_state_start();
+void magic_rcu_quiescent_state_end();
+
+void magic_rcu_init();
+void magic_synchronize_rcu();
+
+void magic_rcu_read_lock();
+void magic_rcu_read_unlock();
+
+#define magic_rcu_has_atomic_quiescent_state() magic_rcu_has_atomic_qs
+extern int magic_rcu_has_atomic_qs;
+
+#endif /* _MAGIC_RCU_H */
diff --git a/minix/llvm/include/magic_real_mem.h b/minix/llvm/include/magic_real_mem.h
new file mode 100644 (file)
index 0000000..1826fc2
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _MAGIC_REAL_MEM_H
+#define _MAGIC_REAL_MEM_H
+
+#include <magic_mem.h>
+
+#define malloc              magic_real_malloc
+#define calloc              magic_real_calloc
+#define free                magic_real_free
+#define realloc             magic_real_realloc
+
+#define posix_memalign      magic_real_posix_memalign
+#define valloc              magic_real_valloc
+#define memalign            magic_real_memalign
+
+#define mmap                magic_real_mmap
+#define munmap              magic_real_munmap
+
+#define brk                 magic_real_brk
+#define sbrk                magic_real_sbrk
+
+#define shmat               magic_real_shmat
+#define shmdt               magic_real_shmdt
+
+#define mmap64              magic_real_mmap64
+#define vm_map_cacheblock   magic_real_vm_map_cacheblock
+
+#endif
+
diff --git a/minix/llvm/include/magic_selement.h b/minix/llvm/include/magic_selement.h
new file mode 100644 (file)
index 0000000..40746c0
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _MAGIC_SELEMENT_H
+#define _MAGIC_SELEMENT_H
+
+#include <magic.h>
+#include <magic_def.h>
+#include <magic_common.h>
+#include <magic_structs.h>
+#include <magic_analysis.h>
+
+/* Magic state element functions. */
+PUBLIC void magic_selement_print_value(const _magic_selement_t *selement);
+PUBLIC unsigned long
+    magic_selement_to_unsigned(const _magic_selement_t *selement);
+PUBLIC long magic_selement_to_int(const _magic_selement_t *selement);
+#if MAGIC_LONG_LONG_SUPPORTED
+PUBLIC unsigned long long
+    magic_selement_to_llu(const _magic_selement_t *selement);
+PUBLIC long long magic_selement_to_ll(const _magic_selement_t *selement);
+#endif
+PUBLIC double magic_selement_to_float(const _magic_selement_t *selement);
+PUBLIC void* magic_selement_to_ptr(const _magic_selement_t *selement);
+PUBLIC void magic_selement_from_unsigned(const _magic_selement_t *selement,
+    unsigned long value);
+PUBLIC void magic_selement_from_int(const _magic_selement_t *selement,
+    long value);
+PUBLIC void magic_selement_from_float(const _magic_selement_t *selement,
+    double value);
+PUBLIC int magic_selement_ptr_value_cast(const _magic_selement_t *src_selement,
+    const _magic_selement_t *dst_selement, void* value_buffer);
+PUBLIC int
+magic_selement_unsigned_value_cast(const _magic_selement_t *src_selement,
+    const _magic_selement_t *dst_selement, void* value_buffer);
+PUBLIC int magic_selement_int_value_cast(const _magic_selement_t *src_selement,
+    const _magic_selement_t *dst_selement, void* value_buffer);
+PUBLIC int
+magic_selement_float_value_cast(const _magic_selement_t *src_selement,
+    const _magic_selement_t *dst_selement, void* value_buffer);
+PUBLIC int magic_selement_value_cast(const _magic_selement_t *src_selement,
+    const _magic_selement_t *dst_selement, void* value_buffer);
+PUBLIC _magic_selement_t*
+magic_selement_get_parent(const _magic_selement_t *selement,
+    _magic_selement_t *parent_selement);
+PUBLIC void magic_selement_fill_from_parent_info(_magic_selement_t *selement,
+    int walk_flags);
+PUBLIC _magic_selement_t*
+magic_selement_from_sentry(struct _magic_sentry *sentry,
+    _magic_selement_t *selement);
+PUBLIC _magic_selement_t*
+magic_selement_from_relative_name(_magic_selement_t *parent_selement,
+    _magic_selement_t *selement, char* name);
+
+
+#endif /* _MAGIC_SELEMENT_H */
diff --git a/minix/llvm/include/magic_sentry.h b/minix/llvm/include/magic_sentry.h
new file mode 100644 (file)
index 0000000..de3928e
--- /dev/null
@@ -0,0 +1,181 @@
+#ifndef _MAGIC_SENTRY_H
+#define _MAGIC_SENTRY_H
+
+#include <magic.h>
+#include <magic_def.h>
+#include <magic_common.h>
+#include <magic_structs.h>
+#include <common/ut/utlist.h>
+
+/* Magic state entry macros. */
+#define MAGIC_SENTRY_SITE_ID(E)                                                \
+    (MAGIC_STATE_FLAG(E, MAGIC_STATE_DYNAMIC) ?                                \
+    MAGIC_DSENTRY_FROM_SENTRY(E)->site_id : MAGIC_DSENTRY_SITE_ID_NULL)
+#define MAGIC_SENTRY_PARENT(E)                                                 \
+    (MAGIC_STATE_FLAG(E, MAGIC_STATE_DYNAMIC) ?                                \
+    MAGIC_DSENTRY_FROM_SENTRY(E)->parent_name : "")
+#define MAGIC_SENTRY_ID(E) ((E)->id)
+#define MAGIC_SENTRY_IS_STRING(E) MAGIC_STATE_FLAG(E,MAGIC_STATE_STRING)
+#define MAGIC_SENTRY_IS_NAMED_STRING(E)                                        \
+    MAGIC_STATE_FLAG(E,MAGIC_STATE_NAMED_STRING)
+#define MAGIC_SENTRY_IS_DSENTRY(E) MAGIC_STATE_FLAG(E,MAGIC_STATE_DYNAMIC)
+/* XXX: Be careful when negating the following macros! */
+#define MAGIC_SENTRY_IS_ALLOC(E)                                               \
+    (MAGIC_SENTRY_IS_DSENTRY(E) && !MAGIC_STATE_FLAG(E,MAGIC_STATE_STACK))
+#define MAGIC_SENTRY_IS_EXT_ALLOC(E)                                           \
+    (MAGIC_SENTRY_IS_ALLOC(E) && !strcmp((E)->name, MAGIC_ALLOC_EXT_NAME) &&   \
+    !strcmp(MAGIC_DSENTRY_FROM_SENTRY(E)->parent_name,                         \
+    MAGIC_ALLOC_EXT_PARENT_NAME))
+#define MAGIC_SENTRY_IS_LIB_ALLOC(E)                                           \
+    (MAGIC_SENTRY_IS_ALLOC(E) &&                                               \
+    !strncmp((E)->name, MAGIC_ALLOC_EXT_NAME, strlen(MAGIC_ALLOC_EXT_NAME)) && \
+    strlen((E)->name) > strlen(MAGIC_ALLOC_EXT_NAME))
+#define MAGIC_SENTRY_PRINT(E, EXPAND_TYPE_STR) do {                            \
+        _magic_printf("SENTRY: (id=%5lu, name=%s, parent=%s, address=0x%08x, " \
+            "flags(RLDCdeTAOSNrwxtpbEZIiP)="                                   \
+            "%c%c%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d, type=",               \
+            (unsigned long) MAGIC_SENTRY_ID(E), (E)->name,                     \
+            MAGIC_SENTRY_PARENT(E), (unsigned) (E)->address,                   \
+            MAGIC_STATE_REGION_C(E), MAGIC_STATE_LIBSPEC_C(E),                 \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_DIRTY),                             \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_CONSTANT),                          \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_DYNAMIC),                           \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_EXT),                               \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_DETACHED),                          \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_ADDR_NOT_TAKEN),                    \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_OUT_OF_BAND),                       \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_STRING),                            \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_NAMED_STRING),                      \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_MODE_R),                            \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_MODE_W),                            \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_MODE_X),                            \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_THREAD_LOCAL),                      \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_MEMPOOL),                           \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_MEMBLOCK),                          \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_EXTERNAL),                          \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_TYPE_SIZE_MISMATCH),                \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_IMMUTABLE),                         \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_INIT),                              \
+            MAGIC_STATE_FLAG(E,MAGIC_STATE_DIRTY_PAGE));                       \
+        MAGIC_TYPE_PRINT((E)->type, EXPAND_TYPE_STR);                          \
+        _magic_printf(")");                                                    \
+    } while(0)
+
+#define MAGIC_SENTRY_OFF_BY_N_NO_DUPLICATES 0x01
+#define MAGIC_SENTRY_OFF_BY_N_POSITIVE      0x02
+#define MAGIC_SENTRY_OFF_BY_N_NEGATIVE      0x04
+#define MAGIC_SENTRY_OFF_BY_N_ZERO          0x08
+#define MAGIC_SENTRY_OFF_BY_N_ALL_N (MAGIC_SENTRY_OFF_BY_N_POSITIVE |          \
+    MAGIC_SENTRY_OFF_BY_N_NEGATIVE | MAGIC_SENTRY_OFF_BY_N_ZERO)
+
+/* Magic state entry array. */
+#define _magic_sentries                     (_magic_vars->sentries)
+#define _magic_sentries_num                 (_magic_vars->sentries_num)
+#define _magic_sentries_str_num             (_magic_vars->sentries_str_num)
+#define _magic_sentries_next_id             (_magic_vars->sentries_next_id)
+
+/* Range lookup index */
+#define magic_sentry_rl_buff                (_magic_vars->sentry_rl_buff)
+#define magic_sentry_rl_buff_offset         (_magic_vars->sentry_rl_buff_offset)
+#define magic_sentry_rl_buff_size           (_magic_vars->sentry_rl_buff_size)
+#define magic_sentry_rl_index               (_magic_vars->sentry_rl_index)
+
+/* Hash vars */
+#define magic_sentry_hash_buff              (_magic_vars->sentry_hash_buff)
+#define magic_sentry_hash_buff_offset       (_magic_vars->sentry_hash_buff_offset)
+#define magic_sentry_hash_buff_size         (_magic_vars->sentry_hash_buff_size)
+#define magic_sentry_hash_head              (_magic_vars->sentry_hash_head)
+
+/* Estimated maximum number of buckets needed. Increase as necessary. */
+#define MAGIC_SENTRY_NAME_EST_MAX_BUCKETS   32768
+/*
+ * Since we don't support freeing memory, we need to allocate _all_ the
+ * intermediate buckets as well. For simplicity, just assume 1 + 2 + 4 + ...
+ * + 2^n, though it will probably be less than that.
+ */
+#define MAGIC_SENTRY_NAME_EST_TOTAL_BUCKETS                                    \
+    ((MAGIC_SENTRY_NAME_EST_MAX_BUCKETS << 1) - 1)
+#define MAGIC_SENTRY_NAME_HASH_OVERHEAD                                        \
+    (MAGIC_SENTRY_NAME_EST_TOTAL_BUCKETS * sizeof(UT_hash_bucket) +            \
+    sizeof(UT_hash_table))
+
+#define MAGIC_SENTRY_TO_HASH_EL(sentry, sentry_hash, sentry_list)              \
+    do {                                                                       \
+        assert(strlen(sentry->name) + 2 * strlen(MAGIC_DSENTRY_ABS_NAME_SEP)   \
+            + 2 < MAGIC_SENTRY_NAME_MAX_KEY_LEN                                \
+            && "Sentry key length too long!");                                 \
+                                                                               \
+        sentry_hash->key[0] = 0;                                               \
+        sprintf(sentry_hash->key, "%s%s%s" MAGIC_ID_FORMAT,                    \
+            MAGIC_DSENTRY_ABS_NAME_SEP, sentry->name,                          \
+            MAGIC_DSENTRY_ABS_NAME_SEP,                                        \
+            (_magic_id_t) MAGIC_DSENTRY_SITE_ID_NULL);                         \
+        sentry_list->sentry = sentry;                                          \
+        sentry_hash->sentry_list = sentry_list;                                \
+    } while (0)
+
+#define MAGIC_DSENTRY_TO_HASH_EL(dsentry, sentry, sentry_hash, sentry_list)    \
+    do {                                                                       \
+        assert(strlen(sentry->name) + strlen(dsentry->parent_name)             \
+            + 2 * strlen(MAGIC_DSENTRY_ABS_NAME_SEP)                           \
+            + 10 +                                                             \
+            + 1 < MAGIC_SENTRY_NAME_MAX_KEY_LEN                                \
+            && "Dsentry key length too long!");                                \
+                                                                               \
+        sentry_hash->key[0] = 0;                                               \
+        sprintf(sentry_hash->key, "%s%s%s%s" MAGIC_ID_FORMAT,                  \
+            dsentry->parent_name, MAGIC_DSENTRY_ABS_NAME_SEP, sentry->name,    \
+            MAGIC_DSENTRY_ABS_NAME_SEP, dsentry->site_id);                     \
+        sentry_list->sentry = sentry;                                          \
+        sentry_hash->sentry_list = sentry_list;                                \
+    } while (0)
+
+/* Lookup functions. */
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_id(_magic_id_t id,
+    struct _magic_dsentry *dsentry_buff);
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_addr(void *addr,
+    struct _magic_dsentry *dsentry_buff);
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_name(char *parent_name,
+    char *name, _magic_id_t site_id, struct _magic_dsentry *dsentry_buff);
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_range(void *addr,
+    struct _magic_dsentry *dsentry_buff);
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_min_off_by_n(void *addr,
+    int flags, long *min_n_ptr, struct _magic_dsentry *dsentry_buff);
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_string(char *string);
+
+/* Lookup index functions. */
+PUBLIC void magic_sentry_rl_build_index(void *buff, size_t buff_size);
+PUBLIC void magic_sentry_rl_destroy_index(void);
+PUBLIC size_t magic_sentry_rl_estimate_index_buff_size(int sentries_num);
+PUBLIC void magic_sentry_rl_print_index(void);
+PUBLIC struct _magic_sentry *magic_sentry_rl_lookup(void* start_addr);
+PUBLIC struct _magic_sentry *magic_sentry_rl_insert(void* start_addr,
+    struct _magic_sentry *sentry);
+PUBLIC struct _magic_sentry *magic_sentry_rl_pred_lookup(void* addr);
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_range_index(void *addr,
+    struct _magic_dsentry *dsentry_buff);
+
+/* Lookup hash functions. */
+PUBLIC void magic_sentry_hash_build(void *buff, size_t buff_size);
+PUBLIC void magic_sentry_hash_destroy(void);
+PUBLIC size_t magic_sentry_hash_estimate_buff_size(int sentries_num);
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_name_hash(char *parent_name,
+    char *name, _magic_id_t site_id, struct _magic_dsentry *dsentry_buff);
+PUBLIC void *magic_sentry_hash_alloc(size_t size);
+PUBLIC void magic_sentry_hash_dealloc(void *object, size_t size);
+PUBLIC struct _magic_sentry_list *magic_sentry_list_lookup_by_name_hash(
+    char *parent_name, char *name, _magic_id_t site_id,
+    struct _magic_dsentry *dsentry_buff);
+
+/* Magic state entry functions. */
+PUBLIC int magic_check_sentry(struct _magic_sentry *entry);
+PUBLIC int magic_check_sentries();
+PUBLIC void magic_print_sentry(struct _magic_sentry* entry);
+PUBLIC void magic_print_sentry_abs_name(struct _magic_sentry *sentry);
+PUBLIC void magic_print_sentries();
+PUBLIC void magic_print_nonstr_sentries();
+PUBLIC void magic_print_str_sentries();
+PUBLIC long magic_sentry_get_off_by_n(struct _magic_sentry* sentry,
+    void *addr, int flags);
+
+#endif /* _MAGIC_SENTRY_H */
diff --git a/minix/llvm/include/magic_splay_tree.h b/minix/llvm/include/magic_splay_tree.h
new file mode 100644 (file)
index 0000000..921195b
--- /dev/null
@@ -0,0 +1,147 @@
+/* A splay-tree datatype.
+   Copyright 1998, 1999, 2000, 2002 Free Software Foundation, Inc.
+   Contributed by Mark Mitchell (mark@markmitchell.com).
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+/* For an easily readable description of splay-trees, see:
+
+     Lewis, Harry R. and Denenberg, Larry.  Data Structures and Their
+     Algorithms.  Harper-Collins, Inc.  1991.
+
+   The major feature of splay trees is that all basic tree operations
+   are amortized O(log n) time for a tree with n nodes.  */
+
+#ifndef _SPLAY_TREE_H
+#define _SPLAY_TREE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef GTY
+#define GTY(X)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif /* ATTRIBUTE_UNUSED */
+
+/* Use typedefs for the key and data types to facilitate changing
+   these types, if necessary.  These types should be sufficiently wide
+   that any pointer or scalar can be cast to these types, and then
+   cast back, without loss of precision.  */
+typedef unsigned long int splay_tree_key;
+typedef unsigned long int splay_tree_value;
+
+/* Forward declaration for a node in the tree.  */
+typedef struct splay_tree_node_s *splay_tree_node;
+
+/* The type of a function which compares two splay-tree keys.  The
+   function should return values as for qsort.  */
+typedef int (*splay_tree_compare_fn) (splay_tree_key, splay_tree_key);
+
+/* The type of a function used to deallocate any resources associated
+   with the key.  */
+typedef void (*splay_tree_delete_key_fn) (splay_tree_key);
+
+/* The type of a function used to deallocate any resources associated
+   with the value.  */
+typedef void (*splay_tree_delete_value_fn) (splay_tree_value);
+
+/* The type of a function used to iterate over the tree.  */
+typedef int (*splay_tree_foreach_fn) (splay_tree_node, void*);
+
+/* The type of a function used to allocate memory for tree root and
+   node structures.  The first argument is the number of bytes needed;
+   the second is a data pointer the splay tree functions pass through
+   to the allocator.  This function must never return zero.  */
+typedef void *(*splay_tree_allocate_fn) (int, void *);
+
+/* The type of a function used to free memory allocated using the
+   corresponding splay_tree_allocate_fn.  The first argument is the
+   memory to be freed; the latter is a data pointer the splay tree
+   functions pass through to the freer.  */
+typedef void (*splay_tree_deallocate_fn) (void *, void *);
+
+/* The nodes in the splay tree.  */
+struct splay_tree_node_s GTY(())
+{
+  /* The key.  */
+  splay_tree_key GTY ((use_param1)) key;
+
+  /* The value.  */
+  splay_tree_value GTY ((use_param2)) value;
+
+  /* The left and right children, respectively.  */
+  splay_tree_node GTY ((use_params)) left;
+  splay_tree_node GTY ((use_params)) right;
+};
+
+/* The splay tree itself.  */
+struct splay_tree_s GTY(())
+{
+  /* The root of the tree.  */
+  splay_tree_node GTY ((use_params)) root;
+
+  /* The comparision function.  */
+  splay_tree_compare_fn comp;
+
+  /* The deallocate-key function.  NULL if no cleanup is necessary.  */
+  splay_tree_delete_key_fn delete_key;
+
+  /* The deallocate-value function.  NULL if no cleanup is necessary.  */
+  splay_tree_delete_value_fn delete_value;
+
+  /* Allocate/free functions, and a data pointer to pass to them.  */
+  splay_tree_allocate_fn allocate;
+  splay_tree_deallocate_fn deallocate;
+  void * GTY((skip)) allocate_data;
+
+};
+typedef struct splay_tree_s *splay_tree;
+
+extern splay_tree splay_tree_new (splay_tree_compare_fn,
+                                  splay_tree_delete_key_fn,
+                                  splay_tree_delete_value_fn);
+extern splay_tree splay_tree_new_with_allocator (splay_tree_compare_fn,
+                                                 splay_tree_delete_key_fn,
+                                                 splay_tree_delete_value_fn,
+                                                 splay_tree_allocate_fn,
+                                                 splay_tree_deallocate_fn,
+                                                 void *);
+extern void splay_tree_delete (splay_tree);
+extern splay_tree_node splay_tree_insert (splay_tree,
+                                          splay_tree_key,
+                                          splay_tree_value);
+extern void splay_tree_remove (splay_tree, splay_tree_key);
+extern splay_tree_node splay_tree_lookup (splay_tree, splay_tree_key);
+extern splay_tree_node splay_tree_predecessor (splay_tree, splay_tree_key);
+extern splay_tree_node splay_tree_successor (splay_tree, splay_tree_key);
+extern splay_tree_node splay_tree_max (splay_tree);
+extern splay_tree_node splay_tree_min (splay_tree);
+extern int splay_tree_foreach (splay_tree, splay_tree_foreach_fn, void*);
+extern int splay_tree_compare_ints (splay_tree_key, splay_tree_key);
+extern int splay_tree_compare_pointers (splay_tree_key, splay_tree_key);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* _SPLAY_TREE_H */
+
diff --git a/minix/llvm/include/magic_structs.h b/minix/llvm/include/magic_structs.h
new file mode 100644 (file)
index 0000000..6634fb9
--- /dev/null
@@ -0,0 +1,312 @@
+#ifndef _MAGIC_STRUCTS_H
+#define _MAGIC_STRUCTS_H
+
+#include <magic_def.h>
+#include <magic_common.h>
+#include <stddef.h>
+#include <common/ut/uthash.h>
+
+/* Magic state type struct. */
+struct _magic_type {
+    _magic_id_t id;
+    char *name;
+    char **names;
+    unsigned num_names;
+    char *type_str;
+    unsigned size;
+    unsigned num_child_types;
+    struct _magic_type **contained_types;
+    struct _magic_type **compatible_types;
+    char **member_names;
+    unsigned *member_offsets;
+    void *value_set;
+    unsigned type_id;
+    int flags;
+    unsigned bit_width;
+    void *ext;
+};
+
+/* Magic state entry struct. */
+struct _magic_sentry {
+    _magic_id_t id;
+    char *name;
+    struct _magic_type *type;
+    int flags;
+    void *address;
+    void *shadow_address;
+};
+
+/* Magic state entry list struct. */
+struct _magic_sentry_list {
+    struct _magic_sentry *sentry;
+    struct _magic_sentry_list *next;
+};
+
+/* Magic state entry hash struct. */
+#define MAGIC_SENTRY_NAME_MAX_KEY_LEN       512
+struct _magic_sentry_hash {
+    struct _magic_sentry_list *sentry_list;
+    char key[MAGIC_SENTRY_NAME_MAX_KEY_LEN];
+    UT_hash_handle hh;
+};
+
+/* Magic state function struct. */
+struct _magic_function {
+    _magic_id_t id;
+    char *name;
+    struct _magic_type *type;
+    int flags;
+    void *address;
+};
+
+/* Magic state function hash struct. */
+struct _magic_function_hash {
+    struct _magic_function *function;
+    void *key;
+    UT_hash_handle hh;
+};
+
+/* Magic dynamic function struct. */
+struct _magic_dfunction {
+    unsigned long magic_number;
+    char *parent_name;
+    struct _magic_function function;
+    struct _magic_dfunction *prev;
+    struct _magic_dfunction *next;
+};
+
+/* Magic dynamic state index struct. */
+struct _magic_dsindex {
+    struct _magic_type *type;
+    char *name;
+    char *parent_name;
+    int flags;
+};
+
+/* Magic dynamic state entry struct. */
+#define MAGIC_DSENTRY_ALLOW_PREV            0
+/*
+ * The name of an externally allocated dsentry will be:
+ * strlen("MAGIC_EXT_ALLOC_NAME") + strlen("MAGIC_ALLOC_NAME_SEP") +
+ * strlen(0xffffffff) + strlen("MAGIC_ALLOC_NAME_SUFFIX") + 1 =
+ * 4 + 1 + 10 + 1 + 1 = 17
+ */
+#define MAGIC_DSENTRY_EXT_NAME_BUFF_SIZE    17
+
+struct _magic_dsentry {
+    unsigned long magic_number;
+    char *parent_name;
+    char name_ext_buff[MAGIC_DSENTRY_EXT_NAME_BUFF_SIZE];
+    struct _magic_sentry sentry;
+    struct _magic_type type;
+    struct _magic_type *type_array[1];
+#if MAGIC_DSENTRY_ALLOW_PREV
+    struct _magic_dsentry *prev;
+#endif
+    struct _magic_dsentry *next;
+    struct _magic_dsentry *next_mpool;
+    struct _magic_dsentry *next_mblock;
+    /*
+     * The following 2 fields are only set if the dsentry
+     * is part of a super object.
+     * See llvm/shared/magic/libst/include/heap.h for more details.
+     */
+#ifndef __MINIX
+    struct _magic_dsentry *next_sobject;
+    void *sobject_base_addr;
+#endif
+    void *ext;
+    unsigned long magic_state;
+    union __alloc_flags {
+        struct {
+            int flags;
+            int prot;
+        } mmap_call;
+#define mmap_flags              mmap_call.flags
+#define mmap_prot               mmap_call.prot
+        struct {
+            int flags;
+            int shmid;
+        } shmat_call;
+#define shmat_flags             shmat_call.flags
+#define shmat_shmid             shmat_call.shmid
+    } alloc_flags;
+#define alloc_mmap_flags        alloc_flags.mmap_call.flags
+#define alloc_mmap_prot         alloc_flags.mmap_call.prot
+#define alloc_shmat_flags       alloc_flags.shmat_call.flags
+#define alloc_shmat_shmid       alloc_flags.shmat_call.shmid
+    _magic_id_t site_id;               /* Identifier of the call at a callsite. */
+};
+
+/* Magic out-of-band dynamic state entry struct. */
+#define MAGIC_MAX_OBDSENTRIES                32
+#define MAGIC_MAX_OBDSENTRY_NAME_LEN         32
+#define MAGIC_MAX_OBDSENTRY_PARENT_NAME_LEN  32
+struct _magic_obdsentry {
+    char name[MAGIC_MAX_OBDSENTRY_NAME_LEN];
+    char parent_name[MAGIC_MAX_OBDSENTRY_PARENT_NAME_LEN];
+    struct _magic_dsentry dsentry;
+};
+EXTERN struct _magic_obdsentry _magic_obdsentries[MAGIC_MAX_OBDSENTRIES];
+
+/* Magic memory pool state struct. */
+#define MAGIC_MAX_MEMPOOLS                  1024
+#define MAGIC_MAX_MEMPOOL_NAME_LEN          32
+#define MAGIC_MEMPOOL_NAME_PREFIX           "_magic_mempool_"
+EXTERN char *const MAGIC_MEMPOOL_NAME_UNKNOWN;
+EXTERN char *const MAGIC_MEMPOOL_NAME_DETACHED;
+
+struct _magic_mpdesc {
+    int is_alive;
+    char name[MAGIC_MAX_MEMPOOL_NAME_LEN];
+    /* pointer to the pool object */
+    void *addr;
+#if MAGIC_MEM_USAGE_OUTPUT_CTL
+    unsigned long dtype_id;
+#endif
+};
+EXTERN struct _magic_mpdesc _magic_mpdescs[MAGIC_MAX_MEMPOOLS];
+
+/* Magic state element. */
+struct _magic_selement_s {
+    struct _magic_dsentry dsentry_buff;
+    struct _magic_sentry *sentry;
+    const struct _magic_type *parent_type;
+    void *parent_address;
+    int child_num;
+    const struct _magic_type *type;
+    void *address;
+    int depth;
+    int num;
+    void *cb_args;
+};
+typedef struct _magic_selement_s _magic_selement_t;
+
+/* Magic external library descriptor. */
+struct _magic_libdesc {
+    const char *name;
+    void *text_range[2];
+    void *data_range[2];
+    void *alloc_address;
+    size_t alloc_size;
+};
+
+/* Magic SO library descriptor. */
+struct _magic_sodesc {
+    struct _magic_libdesc lib;
+    struct _magic_sodesc *prev;
+    struct _magic_sodesc *next;
+};
+
+/* Magic DSO library descriptor. */
+struct _magic_dsodesc {
+    struct _magic_libdesc lib;
+    void *handle;
+    int ref_count;
+    struct _magic_dsodesc *prev;
+    struct _magic_dsodesc *next;
+};
+
+/* Magic vars. */
+struct _magic_vars_t {
+
+    /* Magic Address Space Randomization (ASRPass) */
+    int asr_seed;
+    int asr_heap_map_do_permutate;
+    int asr_heap_max_offset;
+    int asr_heap_max_padding;
+    int asr_map_max_offset_pages;
+    int asr_map_max_padding_pages;
+
+    /* Magic type array. */
+    struct _magic_type *types;
+    int types_num;
+    _magic_id_t types_next_id;
+
+    /* Magic function array. */
+    struct _magic_function *functions;
+    int functions_num;
+    _magic_id_t functions_next_id;
+
+    /* Magic state entry array. */
+    struct _magic_sentry *sentries;
+    int sentries_num;
+    int sentries_str_num;
+    _magic_id_t sentries_next_id;
+
+    /* Magic dynamic state index array. */
+    struct _magic_dsindex *dsindexes;
+    int dsindexes_num;
+
+    /* Magic dynamic state entry list. */
+    struct _magic_dsentry *first_dsentry;
+    unsigned long num_dead_dsentries;
+    unsigned long size_dead_dsentries;
+
+    /* Magic memory pool dynamic state entry list. */
+    struct _magic_dsentry *first_mempool_dsentry;
+
+    /* Magic dynamic function list. */
+    struct _magic_dfunction *first_dfunction;
+    struct _magic_dfunction *last_dfunction;
+    int dfunctions_num;
+
+    /* Magic SO library descriptor list. */
+    struct _magic_sodesc *first_sodesc;
+    struct _magic_sodesc *last_sodesc;
+    int sodescs_num;
+
+    /* Magic DSO library descriptor list. */
+    struct _magic_dsodesc *first_dsodesc;
+    struct _magic_dsodesc *last_dsodesc;
+    int dsodescs_num;
+
+    /* Magic stack-related variables. */
+    struct _magic_dsentry *first_stack_dsentry;
+    struct _magic_dsentry *last_stack_dsentry;
+
+    /* Magic memory ranges */
+    void *null_range[2];
+    void *data_range[2];
+    void *heap_range[2];
+    void *map_range[2];
+    void *shm_range[2];
+    void *stack_range[2];
+    void *text_range[2];
+
+    void *sentry_range[2];
+    void *function_range[2];
+    void *dfunction_range[2];
+
+    void *heap_start;
+    void *heap_end;
+    int update_dsentry_ranges;
+    int update_dfunction_ranges;
+
+    /* Range lookup index */
+    void *sentry_rl_buff;
+    size_t sentry_rl_buff_offset;
+    size_t sentry_rl_buff_size;
+    void *sentry_rl_index;
+
+    /* Sentry hash */
+    void *sentry_hash_buff;
+    size_t sentry_hash_buff_offset;
+    size_t sentry_hash_buff_size;
+    void *sentry_hash_head;
+
+    /* Function hash */
+    void *function_hash_buff;
+    size_t function_hash_buff_offset;
+    size_t function_hash_buff_size;
+    void *function_hash_head;
+
+    /*
+     * Don't call malloc() in magic_malloc_positioned().
+     * Used in ST after RAW COPY.
+     */
+    int fake_malloc;
+};
+
+
+#endif /* _MAGIC_STRUCTS_H */
diff --git a/minix/llvm/include/st/callback.h b/minix/llvm/include/st/callback.h
new file mode 100644 (file)
index 0000000..9287508
--- /dev/null
@@ -0,0 +1,127 @@
+#ifndef ST_CALLBACK_H
+#define ST_CALLBACK_H
+
+#include <st/state_transfer.h>
+
+#define NUM_CB_ARRAYS     8
+#define MAX_NUM_CBS       20
+
+/* Struct for holding info for selement transfer callbacks. */
+struct st_cb_info {
+    _magic_selement_t *local_selement;
+    _magic_selement_t *local_selements;
+    int walk_flags;
+    int st_cb_flags;
+    int *st_cb_saved_flags;
+    st_init_info_t *init_info;
+};
+
+/* Callback type definitions and call registration helpers. */
+
+#define CALLBACK_PREFIX st
+#undef CALLBACK_FAMILY
+#include <st/cb_template.h>
+
+DEFINE_DECL_CALLBACK(void *, pages_allocate, (st_init_info_t *info, uint32_t *phys, int num_pages));
+DEFINE_DECL_CALLBACK(void, pages_free, (st_init_info_t *info, st_alloc_pages *current_page));
+DEFINE_DECL_CALLBACK(int, state_cleanup, (void));
+typedef magic_sentry_analyze_cb_t st_cb_state_checking_t;
+PUBLIC  void st_setcb_state_checking(st_cb_state_checking_t cb);
+DEFINE_DECL_CALLBACK(void, selement_map, (_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping));
+DEFINE_DECL_CALLBACK_CUSTOM(int, selement_transfer, (_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info), (CALLBACK_TYPENAME(selement_transfer) cb, int flags));
+
+/* Struct for holding state transfer callback functions. */
+struct st_cbs_t {
+    st_cb_pages_allocate_t    st_cb_pages_allocate;
+    st_cb_pages_free_t        st_cb_pages_free;
+    st_cb_state_cleanup_t     st_cb_state_cleanup;
+    st_cb_state_checking_t    st_cb_state_checking;
+    st_cb_selement_map_t      st_cb_selement_map;
+    st_cb_selement_transfer_t st_cb_selement_transfer[NUM_CB_ARRAYS][MAX_NUM_CBS];
+};
+
+/* Predefined callback implementations. */
+PUBLIC void *st_cb_pages_allocate(st_init_info_t *info, uint32_t *phys, int num_pages);
+PUBLIC void st_cb_pages_free(st_init_info_t *info, st_alloc_pages *current_page);
+PUBLIC int st_cb_state_cleanup_null(void);
+PUBLIC int st_cb_state_checking_null(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args);
+PUBLIC int st_cb_state_checking_print(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args);
+PUBLIC int st_cb_state_checking_panic(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args);
+
+PUBLIC int st_cb_transfer_sentry_default(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC int st_cb_transfer_typename_default(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC int st_cb_transfer_walkable(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC int st_cb_transfer_ptr(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC int st_cb_transfer_identity(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC int st_cb_transfer_cond_identity(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC int st_cb_transfer_nonptr(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC int st_cb_transfer_struct(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC int st_cb_transfer_selement_base(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC int st_cb_transfer_selement_generic(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+
+PUBLIC void st_cb_map_from_parent_array_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+PUBLIC void st_cb_map_child_array_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+PUBLIC void st_cb_map_from_parent_union_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+PUBLIC void st_cb_map_child_union_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+PUBLIC void st_cb_map_from_parent_struct_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+PUBLIC void st_cb_map_child_struct_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+PUBLIC void st_cb_map_child_primitive_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+PUBLIC void st_cb_map_child_ptr_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+PUBLIC void st_cb_map_from_parent_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+PUBLIC void st_cb_map_child_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+PUBLIC void st_cb_map_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+
+/* Macros for callbacks not defined statically. */
+#define ST_CB_SELEMENT_TRANSFER_EMPTY  {{0}}
+
+/* Macros for predefined callback implementations. */
+#define ST_CB_PAGES_ALLOCATE_DEFAULT   st_cb_pages_allocate
+#define ST_CB_PAGES_FREE_DEFAULT       st_cb_pages_free
+#define ST_CB_STATE_CLEANUP_DEFAULT    st_cb_state_cleanup_null
+#define ST_CB_STATE_CHECKING_DEFAULT   st_cb_state_checking_print
+#define ST_CB_SELEMENT_MAP_DEFAULT     st_cb_map_selement_generic
+
+#define ST_CB_PRINT st_cb_print
+
+#define ST_TYPE_NAME_KEY(TYPE) ((char *) (TYPE)->ext)
+
+#define ST_TYPE_NAME_MATCH(REGISTERED_TYPE_NAME_KEY, KEY)                      \
+    (REGISTERED_TYPE_NAME_KEY == KEY)
+#define ST_TYPE_NAME_MATCH_ANY(REGISTERED_TYPE_NAME_KEYS, KEY)                 \
+    st_type_name_match_any(REGISTERED_TYPE_NAME_KEYS, KEY)
+#define ST_SENTRY_NAME_MATCH(SENTRY_WILDCARD_NAME, NAME)                       \
+    (!st_strcmp_wildcard(SENTRY_WILDCARD_NAME, NAME))
+#define ST_SENTRY_NAME_MATCH_ANY(SENTRY_WILDCARD_NAMES, NAME)                  \
+    st_sentry_name_match_any(SENTRY_WILDCARD_NAMES, NAME)
+#define ST_DSENTRY_PARENT_NAME_MATCH(DSENTRY_WILDCARD_PARENT_NAME, PARENT_NAME)\
+    (!st_strcmp_wildcard(DSENTRY_WILDCARD_PARENT_NAME, PARENT_NAME))
+#define ST_DSENTRY_PARENT_NAME_MATCH_ANY(DSENTRY_WILDCARD_PARENT_NAMES,        \
+    PARENT_NAME)                                                               \
+    st_dsentry_parent_name_match_any(DSENTRY_WILDCARD_PARENT_NAMES, PARENT_NAME)
+
+#define ST_CB_TYPE_TYPENAME 1
+#define ST_CB_TYPE_SENTRY   2
+#define ST_CB_TYPE_SELEMENT 4
+#define ST_CB_NOT_PROCESSED 1000
+
+#define ST_CB_CHECK_ONLY    0x01
+#define ST_CB_PRINT_DBG     0x02
+#define ST_CB_PRINT_ERR     0x04
+#define ST_CB_FORCE_IXFER   0x08
+#define ST_CB_DEFAULT_FLAGS (ST_CB_PRINT_DBG|ST_CB_PRINT_ERR)
+#define ST_CB_FLAG(F) (cb_info->st_cb_flags & F)
+
+#define ST_CB_DBG ST_CB_PRINT_DBG
+#define ST_CB_ERR ST_CB_PRINT_ERR
+#define ST_CB_PRINT_LEVEL(L) ST_CB_FLAG(L)
+#define ST_CB_LEVEL_TO_STR(L)               \
+    (L == ST_CB_DBG ? "DEBUG" :             \
+     L == ST_CB_ERR ? "ERROR" : "???")
+
+#endif /* ST_CALLBACK_H */
diff --git a/minix/llvm/include/st/cb_template.h b/minix/llvm/include/st/cb_template.h
new file mode 100644 (file)
index 0000000..bf3954b
--- /dev/null
@@ -0,0 +1,28 @@
+#undef xglue
+#undef glue
+#undef CALLBACK_TYPENAME
+#undef CALLBACK_SETTERNAME
+#undef DEFINE_CALLBACK
+#undef DECLARE_CALLBACK
+
+#define xglue(x, y) x ## y
+#define glue(x, y) xglue(x, y)
+
+#ifdef CALLBACK_FAMILY
+#define CALLBACK_TYPENAME(name) glue(glue(glue(glue(glue(CALLBACK_PREFIX, _cb_), CALLBACK_FAMILY), _), name), _t)
+#define CALLBACK_SETTERNAME(name) glue(glue(glue(glue(CALLBACK_PREFIX, _setcb_), CALLBACK_FAMILY), _), name)
+#else
+#define CALLBACK_TYPENAME(name) glue(glue(glue(CALLBACK_PREFIX, _cb_), name), _t)
+#define CALLBACK_SETTERNAME(name) glue(glue(CALLBACK_PREFIX, _setcb_), name)
+#endif
+
+#define DECLARE_CALLBACK(ret_type, name, args)                              \
+typedef ret_type(*CALLBACK_TYPENAME(name))args
+
+#define DEFINE_DECL_CALLBACK(ret_type, name, args)                          \
+DECLARE_CALLBACK(ret_type, name, args);                                     \
+void CALLBACK_SETTERNAME(name)(CALLBACK_TYPENAME(name) cb)
+
+#define DEFINE_DECL_CALLBACK_CUSTOM(ret_type, name, args, setter_args)      \
+DECLARE_CALLBACK(ret_type, name, args);                                     \
+void CALLBACK_SETTERNAME(name)setter_args
diff --git a/minix/llvm/include/st/metadata_transfer.h b/minix/llvm/include/st/metadata_transfer.h
new file mode 100644 (file)
index 0000000..371731d
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef METADATA_TRANSFER_H
+#define METADATA_TRANSFER_H
+
+#include <st/state_transfer.h>
+
+/* Metadata transfer and adjustment functions */
+PRIVATE int transfer_metadata_functions(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars,
+    struct _magic_vars_t *remote_magic_vars,
+    st_counterparts_t *counterparts);
+PRIVATE int transfer_metadata_dfunctions(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars,
+    struct _magic_vars_t *remote_magic_vars,
+    st_counterparts_t *counterparts);
+PRIVATE int transfer_metadata_type_members(st_init_info_t *info,
+    struct _magic_type *type, struct _magic_vars_t *cached_magic_vars,
+    struct _magic_vars_t *remote_magic_vars);
+PRIVATE int transfer_metadata_sentries(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars,
+    struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts,
+    int *max_buff_sz);
+PRIVATE int transfer_metadata_sentry_members(st_init_info_t *info,
+    struct _magic_sentry *sentry);
+
+PRIVATE int pair_metadata_types(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars,
+    st_counterparts_t *counterparts, int allow_unpaired_types);
+PRIVATE int pair_metadata_functions(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts);
+PRIVATE int pair_metadata_sentries(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts);
+#if !ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
+PRIVATE int allocate_pair_metadata_dsentries(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts);
+#else
+PRIVATE int allocate_pair_metadata_dsentries_from_raw_copy(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts);
+#endif
+
+/* metadata transfer helper functions */
+PRIVATE int md_transfer_str(st_init_info_t *info, char **str_pt);
+#define MD_TRANSFER_STR(INFO, STR_PT)                                          \
+    do {                                                                       \
+        if (md_transfer_str(INFO, STR_PT)) {                                   \
+            printf("%s, line %d. md_transfer_str(): ERROR transferring.\n",    \
+                __FILE__, __LINE__);                                           \
+            return EGENERIC;                                                   \
+        }                                                                      \
+    } while(0)
+PRIVATE int md_transfer(st_init_info_t *info, void *from, void **to, int len);
+#define MD_TRANSFER(INFO, FROM, TO, LEN)                                       \
+    do {                                                                       \
+        if (md_transfer(INFO, FROM, TO, LEN)) {                                \
+            printf("%s, line %d. md_transfer(): ERROR transferring.\n",        \
+                __FILE__, __LINE__);                                           \
+            return EGENERIC;                                                   \
+        }                                                                      \
+    } while(0)
+
+#endif /* METADATA_TRANSFER_H */
diff --git a/minix/llvm/include/st/os_callback.h b/minix/llvm/include/st/os_callback.h
new file mode 100644 (file)
index 0000000..590a224
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef ST_OS_CALLBACK_H
+#define ST_OS_CALLBACK_H
+
+#include <magic_analysis.h>
+
+/* Callback type definitions and call registration helpers. */
+
+#define CALLBACK_PREFIX st
+#define CALLBACK_FAMILY os
+#include <st/cb_template.h>
+
+DEFINE_DECL_CALLBACK(void, panic, (const char *fmt, ...));
+DEFINE_DECL_CALLBACK(int, old_state_table_lookup, (void *state_info_opaque, void *vars));
+DEFINE_DECL_CALLBACK(int, copy_state_region, (void *state_info_opaque, uint32_t address, size_t size, uint32_t dst_address));
+DEFINE_DECL_CALLBACK(void *, alloc_contig, (size_t len, int flags, uint32_t *phys));
+DEFINE_DECL_CALLBACK(int, free_contig, (void *ptr, size_t length));
+DEFINE_DECL_CALLBACK(char *, debug_header, (void));
+
+/* Default callback values. */
+#define ST_CB_OS_PANIC_EMPTY                    NULL
+#define ST_CB_OS_OLD_STATE_TABLE_LOOKUP_EMPTY   NULL
+#define ST_CB_OS_COPY_STATE_REGION_EMPTY        NULL
+#define ST_CB_OS_ALLOC_CONTIG_EMPTY             NULL
+#define ST_CB_OS_FREE_CONTIG_EMPTY              NULL
+#define ST_CB_OS_DEBUG_HEADER_EMPTY             NULL
+
+struct st_cbs_os_t {
+    CALLBACK_TYPENAME(panic)                    panic;
+    CALLBACK_TYPENAME(old_state_table_lookup)   old_state_table_lookup;
+    CALLBACK_TYPENAME(copy_state_region)        copy_state_region;
+    CALLBACK_TYPENAME(alloc_contig)             alloc_contig;
+    CALLBACK_TYPENAME(free_contig)              free_contig;
+    CALLBACK_TYPENAME(debug_header)             debug_header;
+};
+
+/* General callback registration helper. */
+PUBLIC void st_setcb_os_all(struct st_cbs_os_t *cbs);
+
+#endif /* ST_OS_CALLBACK_H */
diff --git a/minix/llvm/include/st/private.h b/minix/llvm/include/st/private.h
new file mode 100644 (file)
index 0000000..e8d1188
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef ST_PRIVATE_H
+#define ST_PRIVATE_H
+
+
+#include <magic.h>
+#include <magic_mem.h>
+#include <magic_analysis.h>
+#include <magic_asr.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include <st/os_callback.h>
+#include <st/state_transfer.h>
+
+/* Data transfer and adjustment functions */
+#if !ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
+PRIVATE int deallocate_nonxferred_dsentries(struct _magic_dsentry *first_dsentry, st_counterparts_t *counterparts);
+#endif
+PRIVATE void deallocate_local_dsentry(struct _magic_dsentry *local_dsentry);
+PRIVATE int allocate_local_dsentry(st_init_info_t *info, struct _magic_dsindex *local_dsindex, int num_elements, int is_type_mismatch, const union __alloc_flags *p_alloc_flags, struct _magic_dsentry** local_dsentry_ptr, struct _magic_dsentry *cached_dsentry, void *ptr);
+
+PRIVATE int check_unpaired_sentry(st_init_info_t *info, struct _magic_sentry* cached_sentry);
+PRIVATE int transfer_data_sentry(st_init_info_t *info, struct _magic_sentry* cached_sentry);
+PRIVATE int transfer_data_selement(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, void *cb_args);
+PRIVATE int lookup_trg_info(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info,
+    _magic_selement_t *cached_trg_selement, _magic_selement_t *local_trg_selement);
+PRIVATE INLINE void st_set_transfer_status(int status_flags, int status_op,
+    struct _magic_sentry *cached_sentry, struct _magic_function *cached_function);
+PRIVATE INLINE void st_map_selement(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping);
+
+/* Buffer allocation */
+PRIVATE void *persistent_mmap(__MA_ARGS__ st_init_info_t *info, void *start, size_t length, int prot, int flags, int fd, off_t offset, struct _magic_dsentry *dsentry);
+
+#endif /* ST_PRIVATE_H */
diff --git a/minix/llvm/include/st/special.h b/minix/llvm/include/st/special.h
new file mode 100644 (file)
index 0000000..7c2a853
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef ST_SPECIAL_H
+#define ST_SPECIAL_H
+
+/* Public functions for special types and regions. */
+PUBLIC void st_register_typename_key(char *key);
+PUBLIC void st_register_typename_keys(char **keys);
+PUBLIC int st_add_special_mmapped_region(void *address, size_t size, char* name);
+PUBLIC int st_del_special_mmapped_region_by_addr(void *address);
+
+#endif /* ST_SPECIAL_H */
diff --git a/minix/llvm/include/st/state_transfer.h b/minix/llvm/include/st/state_transfer.h
new file mode 100644 (file)
index 0000000..4ff023c
--- /dev/null
@@ -0,0 +1,362 @@
+#ifndef ST_STATE_TRANSFER_H
+#define ST_STATE_TRANSFER_H
+
+
+#include <magic.h>
+#include <magic_mem.h>
+#include <magic_analysis.h>
+#include <magic_asr.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#ifdef __MINIX
+#include <minix/com.h>
+#include <minix/sef.h>
+#endif
+
+/*
+ * Used for debugging: Iterate the type transformations X times.
+ */
+#define MAGIC_ST_TYPE_TRANS_ITERATIONS      1
+
+#include <st/os_callback.h>
+#include <st/special.h>
+
+#define ST_LU_ASR                           (1 << 1)
+#define ST_LU_NOMMAP                        (1 << 2)
+
+/*
+ * Type definitions. These need to be OS independent.
+ */
+typedef struct _st_init_info_t {
+    int flags;
+    void *init_buff_start;
+    void *init_buff_cleanup_start;
+    size_t init_buff_len;
+    struct st_cbs_os_t st_cbs_os;
+    void *info_opaque;
+} st_init_info_t;
+
+typedef struct st_alloc_pages {
+    int num_pages;
+    void *virt_addr;
+    uint32_t phys_addr;
+    struct st_alloc_pages *previous;
+} st_alloc_pages;
+
+#include <st/callback.h>
+
+/* struct for holding a mapping between pointers */
+typedef struct {
+    void *counterpart;
+} st_ptr_mapping;
+
+/* struct for holding arrays of local counterparts to cached variables */
+typedef struct {
+    st_ptr_mapping *functions;
+    int functions_size;
+    st_ptr_mapping *types;
+    st_ptr_mapping *ptr_types;
+    int types_size;
+    st_ptr_mapping *sentries;
+    st_ptr_mapping *sentries_data;
+    int sentries_size;
+} st_counterparts_t;
+
+#define ST_STATE_CHECKING_DEFAULT_MAX_CYCLES        LONG_MAX
+#define ST_STATE_CHECKING_DEFAULT_MAX_VIOLATIONS          50
+
+#define ST_SEL_ANALYZE_FLAGS (MAGIC_SEL_ANALYZE_ALL & (~MAGIC_SEL_ANALYZE_OUT_OF_BAND))
+
+#define ST_MAX_COMPATIBLE_TYPES 32
+
+/* Fields of _magic_vars_t that need to be zeroed out after transferring. */
+#define ST_MAGIC_VARS_PTR_CLEAR_LIST                                           \
+    __X(first_sodesc), __X(last_sodesc),                                       \
+    __X(first_dsodesc), __X(last_dsodesc),                                     \
+    __X(sentry_rl_buff), __X(sentry_rl_index),                                 \
+    __X(sentry_hash_buff), __X(sentry_hash_head),                              \
+    __X(function_hash_buff), __X(function_hash_head)
+
+/* Public utility functions. */
+PUBLIC int st_strcmp_wildcard(char *with_wildcard, char *without_wildcard);
+PUBLIC void st_cb_print(int level, char *msg, _magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC void st_map_str_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr);
+PUBLIC void st_map_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr);
+PUBLIC void st_lookup_sentry_pair(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr);
+PUBLIC void st_add_sentry_pair(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry);
+PUBLIC int st_add_sentry_pair_alloc_by_dsindex(st_init_info_t *info, struct _magic_sentry *cached_sentry, struct _magic_dsindex *local_dsindex, int num_elements, const union __alloc_flags *p_alloc_flags);
+PUBLIC void st_map_functions(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr);
+PUBLIC void st_lookup_function_pair(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr);
+PUBLIC void st_add_function_pair(struct _magic_function *cached_function, struct _magic_function *local_function);
+PUBLIC int st_sentry_equals(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry);
+PUBLIC int st_function_equals(struct _magic_function *cached_function, struct _magic_function *local_function);
+PUBLIC void st_print_sentry_diff(st_init_info_t *info, struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry, int raw_diff, int print_changed);
+PUBLIC void st_print_function_diff(st_init_info_t *info, struct _magic_function *cached_function, struct _magic_function *local_function, int raw_diff, int print_changed);
+PUBLIC void st_cb_selement_type_cast(const struct _magic_type* new_selement_type, const struct _magic_type* new_local_selement_type, _magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+PUBLIC void st_map_local_selement_from_child_num(_magic_selement_t *local_selement, struct st_cb_info *cb_info, int child_num);
+
+/* Stack refs save/restore. */
+PUBLIC void st_stack_refs_save_restore(char *stack_buff, int is_save);
+
+#define st_stack_refs_save(B)    st_stack_refs_save_restore(B,1)
+#define st_stack_refs_restore(B) st_stack_refs_save_restore(B,0)
+
+#define ST_STACK_REFS_BUFF_SIZE (sizeof(struct st_stack_refs_buff))
+
+/*
+ * The stack pointers to the environment and arguments differ from MINIX
+ * to Linux.
+ */
+#if defined(__MINIX)
+#define ST_STACK_REFS_INT_NUM       3
+#define ST_STACK_REFS_INT_LIST \
+    __X(environ), __X(env_argv), __X(env_argc)
+#define ST_STACK_REFS_CUSTOM_NUM    0
+#define ST_STACK_REFS_CUSTOM_LIST
+
+#else
+/*
+ * TODO: Complete the list of Linux stack pointer aliases.
+ */
+#define ST_STACK_REFS_INT_NUM       3
+#define ST_STACK_REFS_INT_LIST __X(_environ), __X(__progname),                 \
+    __X(__progname_full)
+
+#ifndef __USE_GNU
+extern char *program_invocation_name, *program_invocation_short_name;
+extern char **environ;
+#endif
+#define ST_STACK_REFS_CUSTOM_NUM    4
+#define ST_STACK_REFS_CUSTOM_LIST __X(environ), __X(__environ),                \
+    __X(program_invocation_name), __X(program_invocation_short_name)
+
+#endif
+
+#define ST_STACK_REFS_NUM (ST_STACK_REFS_INT_NUM + ST_STACK_REFS_CUSTOM_NUM)
+
+struct st_stack_refs_buff {
+    struct _magic_dsentry *first_stack_dsentry;
+    struct _magic_dsentry *last_stack_dsentry;
+    struct _magic_obdsentry first_stack_obdsentry_buff;
+    void* stack_range[2];
+    int stack_int_refs[ST_STACK_REFS_NUM];
+};
+
+/* Public functions for metadata transfer. */
+PUBLIC int st_transfer_metadata_types(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars,
+    struct _magic_vars_t *remote_magic_vars,
+    st_counterparts_t *counterparts);
+PUBLIC int st_transfer_metadata_dsentries(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars,
+    struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts,
+    int *max_buff_sz, int *dsentries_num);
+
+/* Public functions for state transfer. */
+PUBLIC int st_state_transfer(st_init_info_t *info);
+PUBLIC void st_msync_all_shm_dsentries(void);
+
+PUBLIC int st_init(st_init_info_t *info);
+PUBLIC void st_set_status_defaults(st_init_info_t *info);
+PUBLIC int st_data_transfer(st_init_info_t *info);
+PUBLIC void st_cleanup(st_init_info_t *info);
+
+PUBLIC void st_set_unpaired_types_ratios(float unpaired_types_ratio, float unpaired_struct_types_ratio);
+
+PUBLIC struct _magic_sentry* st_cached_to_remote_sentry(st_init_info_t *info, struct _magic_sentry *cached_sentry);
+
+PUBLIC void st_print_sentries_diff(st_init_info_t *info, int raw_diff, int print_changed);
+PUBLIC void st_print_dsentries_diff(st_init_info_t *info, int raw_diff, int print_changed);
+PUBLIC void st_print_functions_diff(st_init_info_t *info, int raw_diff, int print_changed);
+PUBLIC void st_print_state_diff(st_init_info_t *info, int raw_diff, int print_changed);
+
+PUBLIC void st_set_status_by_state_flags(int status_flags, int status_op, int match_state_flags, int skip_state_flags);
+PUBLIC int st_set_status_by_function_ids(int status_flags, int status_op, unsigned long *ids);
+PUBLIC int st_set_status_by_sentry_ids(int status_flags, int status_op, unsigned long *ids);
+PUBLIC int st_set_status_by_names(int status_flags, int status_op, char **parent_names, char **names, _magic_id_t *dsentry_site_ids);
+PUBLIC int st_set_status_by_local_addrs(int status_flags, int status_op, void **addrs);
+PUBLIC void st_set_status_by_sentry(int status_flags, int status_op, void *cached_sentry);
+PUBLIC void st_set_status_by_function(int status_flags, int status_op, void *cached_function);
+PUBLIC int st_set_status_by_function_id(int status_flags, int status_op, unsigned long id);
+PUBLIC int st_set_status_by_sentry_id(int status_flags, int status_op, unsigned long id);
+PUBLIC int st_set_status_by_name(int status_flags, int status_op, char *parent_name, char *name, _magic_id_t dsentry_site_id);
+PUBLIC int st_set_status_by_local_addr(int status_flags, int status_op, void *addr);
+
+PUBLIC int st_pair_by_function_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op);
+PUBLIC int st_pair_by_sentry_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op);
+PUBLIC int st_pair_by_names(char **cached_parent_names, char **cached_names, char **local_parent_names, char **local_names, _magic_id_t *dsentry_site_ids, int status_flags, int status_op);
+PUBLIC void st_pair_by_sentry(void *cached_sentry, void *local_sentry, int status_flags, int status_op);
+PUBLIC void st_pair_by_function(void *cached_function, void* local_function, int status_flags, int status_op);
+PUBLIC int st_pair_alloc_by_dsindex(st_init_info_t *info, void *cached_sentry, void *local_dsindex, int num_elements, const union __alloc_flags *p_alloc_flags, int status_flags, int status_op);
+PUBLIC int st_pair_by_function_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op);
+PUBLIC int st_pair_by_sentry_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op);
+PUBLIC int st_pair_by_name(char *cached_parent_name, char *cached_name, char *local_parent_name, char *local_name, _magic_id_t dsentry_site_id, int status_flags, int status_op);
+PUBLIC int st_pair_by_alloc_name(st_init_info_t *info, char *cached_parent_name, char *cached_name, _magic_id_t cached_dsentry_site_id, char *local_parent_name, char *local_name, _magic_id_t local_dsentry_site_id, int num_elements, const union __alloc_flags *p_alloc_flags, int status_flags, int status_op);
+PUBLIC int st_pair_by_alloc_name_policies(st_init_info_t *info, char *cached_parent_name, char *cached_name, _magic_id_t cached_dsentry_site_id, char *local_parent_name, char *local_name, _magic_id_t local_dsentry_site_id, int num_elements, const union __alloc_flags *p_alloc_flags, int alloc_policies, int status_flags, int status_op);
+
+/* Public functions for state checking. */
+PUBLIC int st_do_state_cleanup(void);
+PUBLIC int st_do_state_checking(void);
+PUBLIC int st_state_checking_before_receive_is_enabled(void);
+PUBLIC int st_state_checking_before_receive_set_enabled(int enabled, int max_cycles, int max_violations);
+
+/* State transfer status flags and operations. */
+#define ST_NEEDS_TRANSFER          0x01
+#define ST_TRANSFER_DONE           0x02
+#define ST_ON_PTRXFER_CASCADE      0x04
+#define ST_ON_PTRXFER_SET_NULL     0x08
+#define ST_ON_PTRXFER_SET_DEFAULT  0x10
+#define ST_ON_PTRXFER_SKIP         0x20
+
+#define ST_OP_NONE        0
+#define ST_OP_ADD         1
+#define ST_OP_DEL         2
+#define ST_OP_SET         3
+#define ST_OP_CLEAR       4
+
+/* State transfer policies. */
+#define ST_DEFAULT_TRANSFER_NONE                0x00000001
+#define ST_DEFAULT_ALLOC_CASCADE_XFER           0x00000002
+#define ST_DEFAULT_SKIP_STACK                   0x00000004
+#define ST_DEFAULT_SKIP_LIB_STATE               0x00000008
+#define ST_TRANSFER_DIRTY_ONLY                  0x00000010
+#define ST_IXFER_UNCAUGHT_UNIONS                0x00000020
+#define ST_REPORT_UNCAUGHT_UNIONS               0x00000040
+#define ST_REPORT_NONXFERRED_ALLOCS             0x00000080
+#define ST_REPORT_NONXFERRED_UNPAIRED_ALLOCS    0x00000100
+#define ST_REPORT_UNPAIRED_SENTRIES             0x00000200
+#define ST_REPORT_UNPAIRED_DSENTRIES            0x00000400
+#define ST_REPORT_UNPAIRED_STRINGS              0x00000800
+#define ST_REPORT_UNPAIRED_SELEMENTS            0x00001000
+#define ST_MAP_NAMED_STRINGS_BY_NAME            0x00002000
+#define ST_MAP_NAMED_STRINGS_BY_CONTENT         0x00004000
+#define ST_MAP_STRINGS_BY_CONTENT               0x00008000
+#define ST_ON_ALLOC_UNPAIR_ERROR                0x00010000
+#define ST_ON_ALLOC_UNPAIR_DEALLOCATE           0x00020000
+#define ST_ON_ALLOC_UNPAIR_IGNORE               0x00040000
+#define ST_DEFAULT_MAP_GUARD_PTRS_TO_ARRAY_END  0x00080000
+#define ST_DEFAULT_MAP_GUARD_PTRS_TO_STR_END    0x00100000
+#define ST_REPORT_PRECISION_LOSS                0x00200000
+#define ST_REPORT_SIGN_CHANGE                   0x00400000
+#define ST_REPORT_SMALLER_ARRAYS                0x00800000
+#define ST_REPORT_LARGER_ARRAYS                 0x01000000
+#define ST_REPORT_SMALLER_STRINGS               0x02000000
+#define ST_REPORT_LARGER_STRINGS                0x04000000
+
+#define ST_REPORT_UNPAIRED_ALL                                                 \
+    (ST_REPORT_UNPAIRED_SENTRIES | ST_REPORT_UNPAIRED_DSENTRIES |              \
+     ST_REPORT_UNPAIRED_STRINGS | ST_REPORT_UNPAIRED_SELEMENTS)
+#define ST_MAP_STRINGS_DEFAULT                                                 \
+    (ST_MAP_NAMED_STRINGS_BY_NAME | ST_MAP_STRINGS_BY_CONTENT)
+#define ST_ON_ALLOC_UNPAIR_DEFAULT          (ST_ON_ALLOC_UNPAIR_ERROR)
+#define ST_ON_ALLOC_UNPAIR_MASK                                                \
+    (ST_ON_ALLOC_UNPAIR_ERROR | ST_ON_ALLOC_UNPAIR_DEALLOCATE |                \
+     ST_ON_ALLOC_UNPAIR_IGNORE)
+#define ST_TYPE_TRANSFORM_DEFAULT                                              \
+    (ST_DEFAULT_MAP_GUARD_PTRS_TO_STR_END | ST_REPORT_PRECISION_LOSS |         \
+     ST_REPORT_SIGN_CHANGE | ST_REPORT_SMALLER_ARRAYS | ST_REPORT_LARGER_ARRAYS)
+
+#define ST_POLICIES_DEFAULT_TRANSFER_ALL                                       \
+    (ST_DEFAULT_ALLOC_CASCADE_XFER | ST_DEFAULT_SKIP_STACK |                   \
+     ST_DEFAULT_SKIP_LIB_STATE | ST_REPORT_NONXFERRED_ALLOCS |                 \
+     ST_REPORT_NONXFERRED_UNPAIRED_ALLOCS | ST_MAP_STRINGS_DEFAULT |           \
+     ST_ON_ALLOC_UNPAIR_DEFAULT | ST_TYPE_TRANSFORM_DEFAULT)
+#define ST_POLICIES_DEFAULT_TRANSFER_NONE                                      \
+    (ST_DEFAULT_TRANSFER_NONE | ST_DEFAULT_SKIP_STACK |                        \
+     ST_DEFAULT_SKIP_LIB_STATE | ST_REPORT_NONXFERRED_ALLOCS |                 \
+     ST_REPORT_NONXFERRED_UNPAIRED_ALLOCS | ST_MAP_STRINGS_DEFAULT |           \
+     ST_ON_ALLOC_UNPAIR_DEFAULT | ST_TYPE_TRANSFORM_DEFAULT)
+#define ST_POLICIES_DEFAULT_TRANSFER_ASR                                       \
+    (ST_POLICIES_DEFAULT_TRANSFER_ALL | ST_REPORT_UNPAIRED_ALL)
+
+#define ST_POLICIES_DEFAULT                 ST_POLICIES_DEFAULT_TRANSFER_ALL
+
+/* Macros for predefined state transfer names. */
+
+#define ADJUST_POINTER(local, remote, pointer) ( (local) +  ((pointer) - (remote)) )
+#define ST_STR_BUFF_SIZE (MAGIC_MAX_NAME_LEN > MAGIC_MAX_TYPE_STR_LEN ? MAGIC_MAX_NAME_LEN : MAGIC_MAX_TYPE_STR_LEN)
+#define USE_PRE_ALLOCATED_BUFFER(INFO) ((INFO)->init_buff_start)
+#define EXEC_WITH_MAGIC_VARS(CMD, MAGIC_VARS)                       \
+    do {                                                            \
+        struct _magic_vars_t *__saved_vars = _magic_vars;           \
+        _magic_vars = (MAGIC_VARS);                                 \
+        CMD;                                                        \
+        _magic_vars = __saved_vars;                                 \
+    } while(0);
+
+#define MAX_NUM_TYPENAMES              20
+
+#define CHECK_SENTITY_PAIRS            1
+#define ST_DEBUG_LEVEL                 1
+#define ST_DEBUG_DATA_TRANSFER         0
+#define CHECK_ASR                      0
+
+#define ST_ALLOW_RAW_UNPAIRED_TYPES            1
+#define ST_UNPAIRED_TYPES_RATIO_DEFAULT        0
+#define ST_UNPAIRED_STRUCT_TYPES_RATIO_DEFAULT 0
+#define FORCE_SOME_UNPAIRED_TYPES              1
+#define ST_TRANSFER_IDENTITY_FOR_NO_INNER_PTRS 1
+
+#ifndef ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
+#define ST_ASSUME_RAW_COPY_BEFORE_TRANSFER     0
+#endif
+
+#if defined(__MINIX)
+#define ST_IS_UNPAIRABLE_TYPE_OS(T) (sef_self_endpoint != VM_PROC_NR || strcmp((T)->name, "void"))
+#else
+#define ST_IS_UNPAIRABLE_TYPE_OS(T) 1
+#endif
+
+#if ST_ALLOW_RAW_UNPAIRED_TYPES
+#define ST_IS_UNPAIRABLE_TYPE(T) (ST_IS_UNPAIRABLE_TYPE_OS(T) && (T)->type_id != MAGIC_TYPE_UNION)
+#else
+#define ST_IS_UNPAIRABLE_TYPE(T) \
+     (ST_IS_UNPAIRABLE_TYPE_OS(T) \
+     && !MAGIC_TYPE_IS_RAW_ARRAY(T) \
+     && !((T)->type_id == MAGIC_TYPE_ARRAY && !strcmp((T)->contained_types[0]->type_str, "i8")) \
+     && !(T)->ext)
+#endif
+
+#define ST_IS_UNPAIRABLE_STRUCT_TYPE(T) \
+    ((T)->type_id == MAGIC_TYPE_STRUCT)
+
+#define ST_FLAGS_PRINT(E) printf(", sf_flags(NDndsc)=%d%d%d%d%d%d", \
+    MAGIC_STATE_EXTF_FLAG(E,ST_NEEDS_TRANSFER), MAGIC_STATE_EXTF_FLAG(E,ST_TRANSFER_DONE), \
+    MAGIC_STATE_EXTF_FLAG(E,ST_ON_PTRXFER_SET_NULL), MAGIC_STATE_EXTF_FLAG(E,ST_ON_PTRXFER_SET_DEFAULT), \
+    MAGIC_STATE_EXTF_FLAG(E,ST_ON_PTRXFER_SKIP), MAGIC_STATE_EXTF_FLAG(E,ST_ON_PTRXFER_CASCADE));
+
+#define ST_SENTRY_PRINT(E,T)   do { MAGIC_SENTRY_PRINT(E, T); ST_FLAGS_PRINT(E); if (MAGIC_SENTRY_IS_STRING(E)) printf(", string=\"%s\"", (ST_SENTRY_IS_CACHED(E) ? st_lookup_str_local_data(E) : (char*)(E)->address)); } while(0)
+#define ST_DSENTRY_PRINT(E,T)  do { MAGIC_DSENTRY_PRINT(E, T); ST_FLAGS_PRINT(&E->sentry); } while(0)
+#define ST_FUNCTION_PRINT(E,T) do { MAGIC_FUNCTION_PRINT(E, T); ST_FLAGS_PRINT(E); } while(0)
+
+#define ST_CHECK_INIT() assert(st_init_done && "st_init() should be called first!")
+
+#define ST_SENTRY_IS_CACHED(E) (MAGIC_SENTRY_ID(E) >= 1 && MAGIC_SENTRY_ID(E) <= st_cached_magic_vars.sentries_num && st_cached_magic_vars.sentries[MAGIC_SENTRY_ID(E)-1].address == (E)->address)
+#define ST_GET_CACHED_COUNTERPART(CE,T,CT,LE) do {           \
+        int i = (CE)->id - 1;                                \
+        assert(i >= 0 && i < st_counterparts.T##_size);      \
+        LE = st_counterparts.CT[i].counterpart;              \
+    } while(0)
+#define ST_SET_CACHED_COUNTERPART(CE,T,CT,LE) do {           \
+        int i = (CE)->id - 1;                                \
+        assert(i >= 0 && i < st_counterparts.T##_size);      \
+        st_counterparts.CT[i].counterpart = LE;              \
+    } while(0)
+#define ST_HAS_CACHED_COUNTERPART(CE,CT) (st_counterparts.CT[(CE)->id - 1].counterpart != NULL)
+
+#define ST_TYPE_IS_STATIC_CACHED_COUNTERPART(CE,LE) (((CE) >= &st_cached_magic_vars.types[0] && (CE) < &st_cached_magic_vars.types[st_cached_magic_vars.types_num]) && st_counterparts.types[(CE)->id - 1].counterpart == (LE))
+#define ST_TYPE_IS_DYNAMIC_CACHED_COUNTERPART(CE,LE) (MAGIC_TYPE_FLAG(CE,MAGIC_TYPE_DYNAMIC) && (CE)->type_id == MAGIC_TYPE_ARRAY && (LE)->type_id == MAGIC_TYPE_ARRAY && (CE)->num_child_types == (LE)->num_child_types && ST_TYPE_IS_STATIC_CACHED_COUNTERPART((CE)->contained_types[0], (LE)->contained_types[0]))
+#define ST_TYPE_IS_CACHED_COUNTERPART(CE,LE) (ST_TYPE_IS_STATIC_CACHED_COUNTERPART(CE,LE) || ST_TYPE_IS_DYNAMIC_CACHED_COUNTERPART(CE,LE))
+#define ST_PTR_TYPE_IS_STATIC_CACHED_COUNTERPART(CE,LE) (((CE) >= &st_cached_magic_vars.types[0] && (CE) < &st_cached_magic_vars.types[st_cached_magic_vars.types_num]) && st_counterparts.ptr_types[(CE)->id - 1].counterpart == (LE))
+#define ST_PTR_TYPE_IS_DYNAMIC_CACHED_COUNTERPART(CE,LE) (MAGIC_TYPE_FLAG(CE,MAGIC_TYPE_DYNAMIC) && (CE)->type_id == MAGIC_TYPE_ARRAY && (LE)->type_id == MAGIC_TYPE_ARRAY && (CE)->num_child_types == (LE)->num_child_types && ST_PTR_TYPE_IS_STATIC_CACHED_COUNTERPART((CE)->contained_types[0], (LE)->contained_types[0]))
+#define ST_PTR_TYPE_IS_CACHED_COUNTERPART(CE,LE) (ST_PTR_TYPE_IS_STATIC_CACHED_COUNTERPART(CE,LE) || ST_PTR_TYPE_IS_DYNAMIC_CACHED_COUNTERPART(CE,LE))
+
+
+/* Buffer allocation */
+PUBLIC void *st_cb_pages_allocate(st_init_info_t *info, uint32_t *phys, int num_pages);
+PUBLIC void st_cb_pages_free(st_init_info_t *info, st_alloc_pages *current_page);
+PUBLIC void *st_buff_allocate(st_init_info_t *info, size_t size);
+PUBLIC void st_buff_cleanup(st_init_info_t *info);
+
+#endif /* ST_STATE_TRANSFER_H */
diff --git a/minix/llvm/include/st/typedefs.h b/minix/llvm/include/st/typedefs.h
new file mode 100644 (file)
index 0000000..739be1f
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef ST_TYPEDEFS_H
+#define ST_TYPEDEFS_H
+
+#include <stdint.h>
+
+/* Typedefs for predefined state transfer names. */
+#define ST_DECLARE_STD_PTR_TYPEDEFS(PREFIX)         \
+    typedef void*           PREFIX ## void_ptr_t;   \
+    typedef char*           PREFIX ## char_ptr_t;   \
+    typedef short*          PREFIX ## short_ptr_t;  \
+    typedef int*            PREFIX ## int_ptr_t;    \
+    typedef long*           PREFIX ## long_ptr_t;   \
+    typedef unsigned char*  PREFIX ## uchar_ptr_t;  \
+    typedef unsigned short* PREFIX ## ushort_ptr_t; \
+    typedef unsigned int*   PREFIX ## uint_ptr_t;   \
+    typedef unsigned long*  PREFIX ## ulong_ptr_t;  \
+    typedef float*          PREFIX ## float_ptr_t;  \
+    typedef double*         PREFIX ## double_ptr_t; \
+    typedef uint8_t*        PREFIX ## u8_ptr_t;     \
+    typedef uint16_t*       PREFIX ## u16_ptr_t;    \
+    typedef uint32_t*       PREFIX ## u32_ptr_t;    \
+    typedef uint64_t*       PREFIX ## u64_ptr_t;    \
+    typedef int8_t*         PREFIX ## i8_ptr_t;     \
+    typedef int16_t*        PREFIX ## i16_ptr_t;    \
+    typedef int32_t*        PREFIX ## i32_ptr_t
+
+#define ST_DECLARE_STD_PTRINT_TYPEDEFS(PREFIX)      \
+    typedef uint32_t        PREFIX ## u32_t;        \
+    typedef int             PREFIX ## int_t;        \
+    typedef long            PREFIX ## long_t;       \
+    typedef unsigned int    PREFIX ## uint_t;       \
+    typedef unsigned long   PREFIX ## ulong_t
+
+#define ST_TYPENAME_NO_TRANSFER_NAMES           "noxfer_*", "pthread_mutex_t", "siginfo_t", "epoll_data_t", "YYSTYPE"
+    ST_DECLARE_STD_PTR_TYPEDEFS(noxfer_);
+#define ST_TYPENAME_IDENTITY_TRANSFER_NAMES     "ixfer_*"
+    ST_DECLARE_STD_PTR_TYPEDEFS(ixfer_);
+#define ST_TYPENAME_CIDENTITY_TRANSFER_NAMES    "cixfer_*"
+    ST_DECLARE_STD_PTR_TYPEDEFS(cixfer_);
+#define ST_TYPENAME_PTR_TRANSFER_NAMES          "pxfer_*"
+    ST_DECLARE_STD_PTRINT_TYPEDEFS(pxfer_);
+#define ST_TYPENAME_STRUCT_TRANSFER_NAMES       "sxfer_*"
+#ifdef __MINIX
+#define ST_SENTRYNAME_NO_TRANSFER_NAMES         "noxfer_*", "sef_*", "st_*", "_brksize", "etext"
+#else
+#define ST_SENTRYNAME_NO_TRANSFER_NAMES         "noxfer_*", "st_*", "_brksize", "etext", "allocatedDescs*", "ep.*" /* nginx specific */
+#define ST_DSENTRYLIB_NO_TRANSFER_NAMES         "*/libst.so", "*/libcommon.so", "*/libtaskctl.so"
+#endif
+#define ST_SENTRYNAME_IDENTITY_TRANSFER_NAMES   "ixfer_*"
+#define ST_SENTRYNAME_CIDENTITY_TRANSFER_NAMES  "cixfer_*"
+#define ST_SENTRYNAME_PTR_TRANSFER_NAMES        "pxfer_*"
+
+
+#endif /* ST_TYPEDEFS_H */
diff --git a/minix/llvm/static/Makefile.settings b/minix/llvm/static/Makefile.settings
new file mode 100644 (file)
index 0000000..56b7057
--- /dev/null
@@ -0,0 +1,80 @@
+# THIS FILE IS AN EDITED VERSION OF A FILE GENERATED BY LLVM-APPS
+# XXX EDIT AT LEAST THIS PART
+_MINIX_ARCH=i386
+_MINIX_ROOT=/home/myname/path/to/minix
+_MINIX_TOOLS_DIR=/home/myname/path/to/obj.i386/tooldir.Linux-myversion
+
+###########################################################
+# llvm-apps settings for Minix binary instrumentation
+###########################################################
+_MINIX_LLVM_DIR=$(_MINIX_ROOT)/minix/llvm
+_MINIX_OBJ_DIR=$(_MINIX_ROOT)/../obj.$(_MINIX_ARCH)
+_MINIX_OBJ_LLVM_DIR=$(_MINIX_ROOT)/../obj_llvm.$(_MINIX_ARCH)
+_MINIX_SYSROOT=$(_MINIX_OBJ_DIR)/destdir.$(_MINIX_ARCH)
+
+###########################################################
+# Main configuration (override in common.overrides.*inc to match your settings)
+###########################################################
+HAVE_LLVM=1
+LLVMBASEDIR=$(_MINIX_LLVM_DIR)
+LLVMPREFIX=$(_MINIX_OBJ_LLVM_DIR)/Release+Asserts
+LLVM_TWOSTEP_LINKING_WITH_GOLD=0
+LLVM_TWOSTEP_LINKING_WITH_GOLD_USES_LLC=0
+LLVM_OUTPUT_TRG_DIR=
+LLVM_CAP_ALL=CAP_AUDIT_CONTROL,CAP_AUDIT_WRITE,CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_DAC_READ_SEARCH,CAP_FOWNER,CAP_FSETID,CAP_IPC_LOCK,CAP_IPC_OWNER,CAP_KILL,CAP_LEASE,CAP_LINUX_IMMUTABLE,CAP_MAC_ADMIN,CAP_MAC_OVERRIDE,CAP_MKNOD,CAP_NET_ADMIN,CAP_NET_BIND_SERVICE,CAP_NET_BROADCAST,CAP_NET_RAW,CAP_SETGID,CAP_SETFCAP,CAP_SETPCAP,CAP_SETUID,CAP_SYS_ADMIN,CAP_SYS_BOOT,CAP_SYS_CHROOT,CAP_SYS_MODULE,CAP_SYS_NICE,CAP_SYS_PACCT,CAP_SYS_PTRACE,CAP_SYS_RAWIO,CAP_SYS_RESOURCE,CAP_SYS_TIME,CAP_SYS_TTY_CONFIG,CAP_SYSLOG,CAP_SYS_MODULE
+###########################################################
+
+###########################################################
+# Common variables
+###########################################################
+ABS_ROOT=$(LLVMBASEDIR)
+
+PERF_PATH=/usr/bin/perf
+LLVMDIR=$(ABS_ROOT)
+LLVMINC=$(LLVMDIR)/include
+LLVMLIB=$(LLVMDIR)/lib
+INSTALL_DIR=$(ABS_ROOT)/bin
+
+LLVMSECTIONIFY_SO=$(INSTALL_DIR)/sectionify.so
+LLVMAOPIFY_SO=$(INSTALL_DIR)/aopify.so
+LLVMMAGIC_ST_IN_LIBST=0
+
+CC=clang
+CXX=clang++
+CFLAGS=-fasynchronous-unwind-tables -g -I$(LLVMINC)
+###########################################################
+
+###########################################################
+# LLVM gold plugin support (see README.llvm for details)
+#
+# Note: LLVMGOLD_PREFIX below should point to a valid LLVM 2.9 (+LLVMGOLD_CC=llvm-gcc) [or LLVM >= 3.0 (+LLVMGOLD_CC=clang)] installation with gold plugin support (binutils >=2.22)
+###########################################################
+LLVMGOLD_HAS_LTO_DISABLE_OPT=1
+LLVMGOLD_PREFIX=$(LLVMPREFIX)
+LLVMGOLD_PLUGIN=$(_MINIX_LLVM_DIR)/bin/LLVMgold.so
+
+LLVMGOLD_CC=$(_MINIX_TOOLS_DIR)/bin/i586-elf32-minix-clang -flto
+LLVMGOLD_CXX=$(_MINIX_TOOLS_DIR)/bin/i586-elf32-minix-clang++ -flto
+LLVMGOLD_AR=ar --plugin $(LLVMGOLD_PLUGIN)
+LLVMGOLD_RANLIB=$(LLVMGOLD_AR) -s
+
+LLVMGOLD_AR_FLAGS=--plugin $(LLVMGOLD_PLUGIN) -cru
+LLVMGOLD_CFLAGS=-fasynchronous-unwind-tables -g -D_MINIX -D_POSIX_SOURCE -D_SYSTEM -Wno-long-long --sysroot=$(_MINIX_SYSROOT) -I$(LLVMINC) -I$(_MINIX_OBJ_LLVM_DIR)/include/llvm -I$(_MINIX_ROOT)/external/bsd/llvm/dist/llvm/include -I$(_MINIX_OBJ_LLVM_DIR)/include -I$(_MINIX_SYSROOT)/usr/include
+LLVMGOLD_LINK=-Wl,--plugin -Wl,$(LLVMGOLD_PLUGIN)
+LLVMGOLD_LINKFLAGS=-Wl,-plugin-opt=-disable-fp-elim -Wl,-plugin-opt=-disable-inlining -Wl,-plugin-opt=also-emit-llvm
+LLVMGOLD_LINKCOMMONFLAGS=-L$(_MINIX_OBJ_DIR)/destdir.$(_MINIX_ARCH)/usr/lib -rdynamic
+LLVMGOLD_LIBS=
+LLVMGOLD_LDFLAGS=$(LLVMGOLD_LINK) $(LLVMGOLD_LINKFLAGS) $(LLVMGOLD_LINKCOMMONFLAGS) $(LLVMGOLD_LIBS)
+LLVMGOLD_OPTFLAGS=-disable-internalize -mem2reg -std-compile-opts
+LLVMGOLD_LLCFLAGS=--disable-fp-elim
+LLVMGOLD_TSLINK_PARTIALFLAGS=-Wl,-r -nostdlib
+LLVMGOLD_TSLINK_FINALFLAGS=-B$(LLVMGOLD_PREFIX)/bfd_bin
+LLVMGOLD_OPTIMIZED=1
+
+###########################################################
+
+BUILD_LLVMAPPS_FOR_MINIX=yes
+GEN_GOLD_PLUGIN=yes
+REBUILD_MINIX=yes
+ARCH_NAME=x86
+ARCH_BITS=32
diff --git a/minix/llvm/static/magic/Makefile b/minix/llvm/static/magic/Makefile
new file mode 100644 (file)
index 0000000..8fac9ee
--- /dev/null
@@ -0,0 +1,29 @@
+#Makefile for creating the magic static library
+
+MODULE = magic
+OBJS = magic.o magic_analysis.o magic_asr.o magic_eval_lib.o magic_eval.o magic_mem.o magic_range.o magic_splay_tree.o magic_sentry.o magic_selement.o
+HEADERS = $(wildcard $(LLVMINC)/*.h) $(wildcard $(LLVMINC)/st/*.h)
+
+USE_SECTIONIFY=YES
+SECTIONIFY_NO_OVERRIDE=yes
+SECTIONIFY_DATA_SECTION_MAP=^_____magic_instr_.*/magic_instr_data,.*/magic_data
+SECTIONIFY_FUNCTION_SECTION_MAP=.*/magic_functions
+
+OBJS += minix/magic_util.o minix/magic_ds.o
+HEADERS += $(wildcard minix/*.h)
+
+OBJS+=magic_st.bcc
+
+include Makefile.inc
+
+CFLAGS += -I$(_MINIX_ROOT)/minix/servers
+
+# XXX: there is essential code in assert() statements, so force asserts on..
+CFLAGS += -UNDEBUG
+
+magic_st.bcc:
+       make -f Makefile.magic_st $@
+
+magic_st.o:
+       make -f Makefile.magic_st $@
+
diff --git a/minix/llvm/static/magic/Makefile.inc b/minix/llvm/static/magic/Makefile.inc
new file mode 100644 (file)
index 0000000..91b99e0
--- /dev/null
@@ -0,0 +1,57 @@
+
+include ../Makefile.settings
+
+MODULE_NAME=$(MODULE).bcc
+
+CFLAGS += $(CXXFLAGS) -Wall -g -Wno-long-long
+CFLAGS += -D__MINIX -D_MINIX_SYSTEM
+
+LLVM_VERSION=$(shell $(LLVMPREFIX)/bin/llvm-config --version | cut -d"." -f1,2 | sed "s/[^0-9]//g")
+
+HAVE_NOCONSTRUCTOR_PRIORITY = $(shell expr $(LLVM_VERSION) \>= 30)
+ifeq ($(HAVE_NOCONSTRUCTOR_PRIORITY),0)
+CFLAGS += -DHAVE_NOCONSTRUCTOR_PRIORITY=1 
+endif
+
+ifeq ($(USE_SECTIONIFY),YES)
+LOPT_FLAGS+=-load=$(LLVMSECTIONIFY_SO) -sectionify -sectionify-no-override -sectionify-data-section-map=$(SECTIONIFY_DATA_SECTION_MAP) -sectionify-function-section-map=$(SECTIONIFY_FUNCTION_SECTION_MAP)
+ifeq (SECTIONIFY_NO_OVERRIDE,YES)
+LOPT_FLAGS+=-sectionify-no-override
+endif
+endif
+
+V?=0
+ifneq ($V,0)
+QUIET=
+ECHO:=@\#
+QMAKE=VERBOSE=1 make
+else
+QUIET= @
+ECHO= echo
+QMAKE=make -s
+endif
+
+$(MODULE_NAME): $(OBJS) $(HEADERS) $(COMMON_BCCS)
+       $(QUIET) $(ECHO) "  [GOLD_LINK] $@.o"
+       $(QUIET) $(LLVMGOLD_CC) $(CFLAGS) $(LLVMGOLD_CFLAGS) $(LLVMGOLD_LDFLAGS) -shared -o $@.o $(OBJS) $(COMMON_BCCS)
+       $(QUIET) $(ECHO) "  [OPT] $@"
+       $(QUIET) $(LLVMPREFIX)/bin/opt $(LOPT_FLAGS) -o $@ $@.o.bc
+
+all: $(MODULE_NAME)
+
+%.o: %.c $(HEADERS)
+       $(QUIET) $(ECHO) "  [GOLD_CC] $<"
+       $(QUIET) $(LLVMGOLD_CC) $(CFLAGS) $(LLVMGOLD_CFLAGS) $(INCLUDES) $(INCLUDES_$<) -c -o $@ $<
+
+install: $(INSTALL_DIR)/$(MODULE_NAME)
+
+$(INSTALL_DIR)/$(MODULE_NAME): $(MODULE_NAME)
+       install -c -D -m 744 $? $@
+
+clean: $(EXTRA_CLEAN)
+       $(QUIET) $(ECHO) "  [RM] *.BCC *.bcc *.bc *.BCL *.BCL.sh *.bcl $(OBJS) *.s $(COMMON_BCCS)"
+       $(QUIET) rm -f *.BCC *.bcc *.bc *.BCL *.BCL.sh *.bcl *.o $(OBJS) *.s $(COMMON_BCCS)
+
+distclean: clean
+       $(QUIET) $(ECHO) "  [RM] $(INSTALL_DIR)/$(MODULE_NAME)"
+       $(QUIET) rm -f $(INSTALL_DIR)/$(MODULE_NAME)
diff --git a/minix/llvm/static/magic/Makefile.magic_st b/minix/llvm/static/magic/Makefile.magic_st
new file mode 100644 (file)
index 0000000..9ec7c54
--- /dev/null
@@ -0,0 +1,11 @@
+
+MODULE = magic_st
+
+OBJS = magic_st.o
+
+USE_SECTIONIFY=YES
+SECTIONIFY_DATA_SECTION_MAP=.*/magic_data_st 
+SECTIONIFY_FUNCTION_SECTION_MAP=.*/magic_functions_st 
+
+include Makefile.inc
+
diff --git a/minix/llvm/static/magic/magic.c b/minix/llvm/static/magic/magic.c
new file mode 100644 (file)
index 0000000..661ff33
--- /dev/null
@@ -0,0 +1,2585 @@
+#include <magic.h>
+#include <magic_mem.h>
+#include <magic_asr.h>
+#include <magic_eval.h>
+#include <magic_analysis.h>
+#include <magic_splay_tree.h>
+#include <stdarg.h>
+#if MAGIC_MEM_USAGE_OUTPUT_CTL
+#include <common/util/time.h>
+#endif
+
+/* Workaround for extern-only structs. */
+#ifndef __MINIX
+#include <stdio.h>
+EXTERN FILE *stdout;
+PUBLIC FILE **UNUSED(_____magic_instr_FILE_unused) = &stdout;
+
+#include <ncurses.h>
+PUBLIC WINDOW *UNUSED(_____magic_instr_WINDOW_unused);
+#endif
+
+#include <netinet/in.h>
+PUBLIC struct in6_addr *UNUSED(_____magic_instr_in6_addr_unused);
+
+/* Magic printf. */
+MAGIC_VAR printf_ptr_t _magic_printf = MAGIC_PRINTF_DEFAULT;
+
+/* Magic lock primitives. */
+PUBLIC magic_lock_t magic_dsentry_lock = NULL;
+PUBLIC magic_unlock_t magic_dsentry_unlock = NULL;
+PUBLIC void *magic_dsentry_lock_args = NULL;
+PUBLIC void *magic_dsentry_unlock_args = NULL;
+
+PUBLIC magic_lock_t magic_dfunction_lock = NULL;
+PUBLIC magic_unlock_t magic_dfunction_unlock = NULL;
+PUBLIC void *magic_dfunction_lock_args = NULL;
+PUBLIC void *magic_dfunction_unlock_args = NULL;
+
+PUBLIC magic_lock_t magic_dsodesc_lock = NULL;
+PUBLIC magic_unlock_t magic_dsodesc_unlock = NULL;
+PUBLIC void *magic_dsodesc_lock_args = NULL;
+PUBLIC void *magic_dsodesc_unlock_args = NULL;
+
+PUBLIC magic_lock_t magic_mpdesc_lock = NULL;
+PUBLIC magic_unlock_t magic_mpdesc_unlock = NULL;
+PUBLIC void *magic_mpdesc_lock_args = NULL;
+PUBLIC void *magic_mpdesc_unlock_args = NULL;
+
+/* Magic vars references. */
+MAGIC_VAR struct _magic_vars_t _magic_vars_buff = {
+
+    /* Address Space Randomization (ASRPass) */
+    0, /* asr_seed */
+    0, /* asr_heap_map_do_permutate */
+    0, /* asr_heap_max_offset */
+    0, /* asr_heap_max_padding */
+    0, /* asr_map_max_offset_pages */
+    0, /* asr_map_max_padding_pages */
+
+    /* Magic type array. */
+    NULL, /* types */
+    0,    /* types_num */
+    0,    /* types_next_id */
+
+    /* Magic function array. */
+    NULL, /* functions */
+    0,    /* functions_num */
+    0,    /* functions_next_id */
+
+    /* Magic state entry array. */
+    NULL, /* sentries */
+    0,    /* sentries_num */
+    0,    /* sentries_str_num */
+    0,    /* sentries_next_id */
+
+    /* Magic dynamic state index array. */
+    NULL, /* dsindexes */
+    0,    /* dsindexes_num */
+
+    /* Magic dynamic state entry list. */
+    NULL, /* first_dsentry */
+    0,    /* num_dead_sentries */
+    0,    /* size_dead_dsentries */
+
+    /* Magic memory pool dynamic state entry list. */
+    NULL, /* first_mempool_dsentry */
+
+    /* Magic dynamic function list. */
+    NULL, /* first_dfunction */
+    NULL, /* last_dfunction */
+    0,    /* dfunctions_num */
+
+    /* Magic SO library descriptor list. */
+    NULL, /* first_sodesc */
+    NULL, /* last_sodesc */
+    0,    /* sodescs_num */
+
+    /* Magic DSO library descriptor list. */
+    NULL, /* first_dsodesc */
+    NULL, /* last_dsodesc */
+    0,    /* dsodescs_num */
+
+    /* Magic stack-related variables. */
+    NULL, /* first_stack_dsentry */
+    NULL, /* last_stack_dsentry */
+
+    /* Magic memory ranges */
+
+    { (void*) ULONG_MAX, (void*) 0 }, /* *null_range[2] */
+    {0,0}, /* *data_range[2] */
+    {0,0}, /* *heap_range[2] */
+    {0,0}, /* *map_range[2] */
+    {0,0}, /* *shm_range[2] */
+    {0,0}, /* *stack_range[2] */
+    {0,0}, /* *text_range[2] */
+
+    {0,0}, /* *sentry_range[2] */
+    {0,0}, /* *function_range[2] */
+    {0,0}, /* *dfunction_range[2] */
+
+    NULL, /* *heap_start */
+    NULL, /* *heap_end */
+    1,     /* update_dsentry_ranges */
+    1,     /* update_dfunction_ranges */
+
+    NULL,  /* sentry_rl_buff */
+    0,     /* sentry_rl_buff_offset */
+    0,     /* sentry_rl_buff_size */
+    NULL,  /* sentry_rl_index */
+
+    NULL,  /* sentry_hash_buff */
+    0,     /* sentry_hash_buff_offset */
+    0,     /* sentry_hash_buff_size */
+    NULL,  /* sentry_hash_head */
+
+    NULL,  /* function_hash_buff */
+    0,     /* function_hash_buff_offset */
+    0,     /* function_hash_buff_size */
+    NULL,  /* function_hash_head */
+
+    0      /* fake_malloc */
+};
+
+PUBLIC struct _magic_vars_t *_magic_vars = &_magic_vars_buff;
+
+/* Magic void ptr and array (force at the least 1 void* and 1 void array in the list of globals). */
+PUBLIC void* MAGIC_VOID_PTR = NULL;
+PUBLIC char MAGIC_VOID_ARRAY[1];
+
+/* Magic special types. */
+MAGIC_VAR struct _magic_type *MAGIC_VOID_PTR_TYPE = NULL;
+MAGIC_VAR struct _magic_type *MAGIC_VOID_PTR_INT_CAST_TYPE = NULL;
+MAGIC_VAR struct _magic_type *MAGIC_VOID_ARRAY_TYPE = NULL;
+MAGIC_VAR struct _magic_type *MAGIC_PTRINT_TYPE = NULL;
+MAGIC_VAR struct _magic_type *MAGIC_PTRINT_ARRAY_TYPE = NULL;
+
+/* Magic annotations. */
+MAGIC_VAR VOLATILE int MAGIC_CALL_ANNOTATION_VAR;
+
+/* Magic status variables. */
+PUBLIC int magic_init_done = 0;
+PUBLIC int magic_libcommon_active = 0;
+PUBLIC int magic_lookup_nested_dsentries = 1;
+PUBLIC int magic_allow_dead_dsentries = MAGIC_ALLOW_DEAD_DSENTRIES_DEFAULT;
+PUBLIC int magic_ignore_dead_dsentries = 0;
+PUBLIC int magic_mmap_dsentry_header_prot = PROT_READ | PROT_WRITE;
+MAGIC_VAR int _magic_enabled = 0;
+MAGIC_VAR int _magic_checkpoint_enabled = 0;
+MAGIC_VAR int _magic_lazy_checkpoint_enabled = 0;
+
+/* Magic out-of-band dsentries. */
+PUBLIC struct _magic_obdsentry _magic_obdsentries[MAGIC_MAX_OBDSENTRIES];
+
+/* Pool management data. */
+PUBLIC struct _magic_mpdesc _magic_mpdescs[MAGIC_MAX_MEMPOOLS];
+
+/* Magic page size. */
+PUBLIC unsigned long magic_sys_pagesize = 0;
+
+/* Private variables. */
+PUBLIC int magic_type_str_print_style = MAGIC_TYPE_STR_PRINT_STYLE_DEFAULT;
+PRIVATE THREAD_LOCAL const struct _magic_type* magic_nested_types[MAGIC_MAX_RECURSIVE_TYPES] = {0};
+PRIVATE THREAD_LOCAL const struct _magic_type* magic_nested_types2[MAGIC_MAX_RECURSIVE_TYPES] = {0};
+PRIVATE THREAD_LOCAL unsigned magic_level = 0;
+PRIVATE THREAD_LOCAL unsigned magic_counter;
+PRIVATE THREAD_LOCAL struct _magic_dsentry magic_dsentry_buff;
+PRIVATE THREAD_LOCAL struct _magic_dfunction magic_dfunction_buff;
+
+/* Magic default stubs. */
+PUBLIC struct _magic_type magic_default_type = {
+    0, "", NULL, 0, "", 0, 0, NULL, NULL, NULL, NULL, NULL, MAGIC_TYPE_OPAQUE, 0, 0
+};
+
+PUBLIC struct _magic_dsentry magic_default_dsentry = {
+    MAGIC_DSENTRY_MNUM, /* magic_number */
+    "", /* parent_name */
+    { 0 }, /* name_ext_buff */
+    { 0, "", NULL, MAGIC_STATE_DYNAMIC, NULL, NULL }, /* sentry */
+    { 0, "", NULL, 0, "", 0, 0, NULL, NULL, NULL, NULL, NULL, MAGIC_TYPE_ARRAY, MAGIC_TYPE_IS_ROOT|MAGIC_TYPE_DYNAMIC, 0 }, /* type */
+    { NULL }, /* type_array */
+#if MAGIC_DSENTRY_ALLOW_PREV
+    NULL, /* prev */
+#endif
+    NULL, /* next */
+    NULL, /* next_mpool */
+    NULL, /* next_mblock */
+#ifndef __MINIX
+    NULL, /* next_sobject */
+    NULL, /* sobject_base_addr */
+#endif
+    NULL, /* ext */
+    MAGIC_DSENTRY_MSTATE_ALIVE, /* magic_state */
+    { { 0, 0 } }, /* alloc_flags */
+    0 /* site_id */
+};
+
+PUBLIC struct _magic_dfunction magic_default_dfunction = {
+    MAGIC_DFUNCTION_MNUM,
+    "",
+    { 0, "", NULL, MAGIC_STATE_DYNAMIC|MAGIC_STATE_TEXT|MAGIC_STATE_CONSTANT, NULL },
+    NULL,
+    NULL
+};
+
+PUBLIC struct _magic_type magic_default_ret_addr_type = {
+    0, "", NULL, 0, "", sizeof(void*), 1, NULL, NULL, NULL, NULL, NULL, MAGIC_TYPE_POINTER, MAGIC_TYPE_IS_ROOT|MAGIC_TYPE_DYNAMIC|MAGIC_TYPE_INT_CAST|MAGIC_TYPE_STRICT_VALUE_SET, 0
+};
+
+/* Magic code reentrant flag. */
+PRIVATE int magic_reentrant = 1;
+
+/*===========================================================================*
+ *                         _magic_vars_addr                        *
+ *===========================================================================*/
+void *_magic_vars_addr()
+{
+    return _magic_vars;
+}
+
+/*===========================================================================*
+ *                         _magic_vars_size                        *
+ *===========================================================================*/
+size_t _magic_vars_size()
+{
+    return sizeof(struct _magic_vars_t);
+}
+
+/*===========================================================================*
+ *                          magic_null_printf                                *
+ *===========================================================================*/
+PUBLIC int magic_null_printf(const char *format, ...)
+{
+  return 0;
+}
+
+#ifndef __MINIX
+/*===========================================================================*
+ *                           magic_err_printf                                *
+ *===========================================================================*/
+PUBLIC int magic_err_printf(const char *format, ...)
+{
+  va_list va;
+  int ret;
+  va_start(va, format);
+  ret = vfprintf(stderr, format, va);
+  va_end(va);
+
+  return ret;
+}
+#endif
+
+/*===========================================================================*
+ *                           magic_set_printf                                *
+ *===========================================================================*/
+PUBLIC void magic_set_printf(printf_ptr_t func_ptr)
+{
+   assert(func_ptr);
+   _magic_printf = func_ptr;
+}
+
+/*===========================================================================*
+ *                           magic_get_printf                                *
+ *===========================================================================*/
+PUBLIC printf_ptr_t magic_get_printf(void)
+{
+   return _magic_printf;
+}
+
+/*===========================================================================*
+ *                        magic_reentrant_enable                             *
+ *===========================================================================*/
+PUBLIC void magic_reentrant_enable(void)
+{
+    magic_reentrant = 1;
+}
+/*===========================================================================*
+ *                        magic_reentrant_disable                            *
+ *===========================================================================*/
+PUBLIC void magic_reentrant_disable(void)
+{
+    magic_reentrant = 0;
+}
+
+/*===========================================================================*
+ *                          magic_assert_failed                              *
+ *===========================================================================*/
+PUBLIC void magic_assert_failed(const char *assertion, const char *file,
+    const char *function, const int line)
+{
+    _magic_printf("Assertion '%s' failed in file %s, function %s(), line %d, pid %d\n",
+        assertion, file, function, line, getpid());
+    abort();
+}
+
+/*===========================================================================*
+ *                         magic_get_sys_pagesize                            *
+ *===========================================================================*/
+PUBLIC unsigned long magic_get_sys_pagesize()
+{
+    if(!magic_sys_pagesize) {
+        magic_sys_pagesize = SYS_PAGESIZE;
+    }
+    return magic_sys_pagesize;
+}
+
+/*===========================================================================*
+ *                   magic_dsentry_set_lock_primitives                       *
+ *===========================================================================*/
+PUBLIC void magic_dsentry_set_lock_primitives(magic_lock_t lock,
+    magic_unlock_t unlock, void *lock_args, void *unlock_args)
+{
+    assert(lock && unlock);
+    magic_dsentry_lock = lock;
+    magic_dsentry_unlock = unlock;
+    magic_dsentry_lock_args = lock_args;
+    magic_dsentry_unlock_args = unlock_args;
+}
+
+/*===========================================================================*
+ *                   magic_dfunction_set_lock_primitives                     *
+ *===========================================================================*/
+PUBLIC void magic_dfunction_set_lock_primitives(magic_lock_t lock,
+    magic_unlock_t unlock, void *lock_args, void *unlock_args)
+{
+    assert(lock && unlock);
+    magic_dfunction_lock = lock;
+    magic_dfunction_unlock = unlock;
+    magic_dfunction_lock_args = lock_args;
+    magic_dfunction_unlock_args = unlock_args;
+}
+
+/*===========================================================================*
+ *                    magic_dsodesc_set_lock_primitives                      *
+ *===========================================================================*/
+PUBLIC void magic_dsodesc_set_lock_primitives(magic_lock_t lock,
+    magic_unlock_t unlock, void *lock_args, void *unlock_args)
+{
+    assert(lock && unlock);
+    magic_dsodesc_lock = lock;
+    magic_dsodesc_unlock = unlock;
+    magic_dsodesc_lock_args = lock_args;
+    magic_dsodesc_unlock_args = unlock_args;
+}
+
+/*===========================================================================*
+ *                 magic_mpdesc_set_lock_primitives                          *
+ *===========================================================================*/
+PUBLIC void magic_mpdesc_set_lock_primitives(magic_lock_t lock,
+    magic_unlock_t unlock, void *lock_args, void *unlock_args)
+{
+    assert(lock && unlock);
+    magic_mpdesc_lock = lock;
+    magic_mpdesc_unlock = unlock;
+    magic_mpdesc_lock_args = lock_args;
+    magic_mpdesc_unlock_args = unlock_args;
+}
+
+/*===========================================================================*
+ *                            magic_types_init                               *
+ *===========================================================================*/
+PRIVATE void magic_types_init()
+{
+    static struct _magic_type _magic_void_ptr_type_buff;
+    static struct _magic_type _magic_void_array_type_buff;
+    static struct _magic_type *_magic_void_array_type_contained_types[1];
+    static struct _magic_type _magic_ptrint_type_buff;
+    static char* _magic_ptrint_type_name = "ptrint";
+    static char _magic_ptrint_type_str_buff[8];
+    static struct _magic_type _magic_ptrint_array_type_buff;
+    static struct _magic_type *_magic_ptrint_array_type_contained_types[1];
+
+    assert(MAGIC_VOID_PTR_TYPE);
+    assert(MAGIC_VOID_PTR_TYPE->size == sizeof(void*));
+    assert(MAGIC_VOID_TYPE->size == sizeof(char));
+
+    MAGIC_VOID_PTR_INT_CAST_TYPE = &_magic_void_ptr_type_buff;
+    *MAGIC_VOID_PTR_INT_CAST_TYPE = *MAGIC_VOID_PTR_TYPE;
+    MAGIC_VOID_PTR_INT_CAST_TYPE->flags |= MAGIC_TYPE_INT_CAST;
+
+    MAGIC_VOID_ARRAY_TYPE = &_magic_void_array_type_buff;
+    *MAGIC_VOID_ARRAY_TYPE = magic_default_type;
+    MAGIC_TYPE_ARRAY_CREATE_FROM_N(MAGIC_VOID_ARRAY_TYPE, MAGIC_VOID_TYPE,
+        _magic_void_array_type_contained_types, 1);
+
+    MAGIC_PTRINT_TYPE = &_magic_ptrint_type_buff;
+    *MAGIC_PTRINT_TYPE = magic_default_type;
+    MAGIC_TYPE_INT_CREATE(MAGIC_PTRINT_TYPE, MAGIC_VOID_PTR_TYPE->size,
+        _magic_ptrint_type_name, _magic_ptrint_type_str_buff);
+
+    MAGIC_PTRINT_ARRAY_TYPE = &_magic_ptrint_array_type_buff;
+    *MAGIC_PTRINT_ARRAY_TYPE = magic_default_type;
+    MAGIC_TYPE_ARRAY_CREATE_FROM_N(MAGIC_PTRINT_ARRAY_TYPE, MAGIC_PTRINT_TYPE,
+        _magic_ptrint_array_type_contained_types, 1);
+}
+
+/*===========================================================================*
+ *                           magic_data_init                                 *
+ *===========================================================================*/
+MAGIC_FUNC void magic_data_init()
+{
+    MAGIC_FUNC_BODY();
+}
+
+/*===========================================================================*
+ *                              magic_init                                   *
+ *===========================================================================*/
+PUBLIC void magic_init(void)
+{
+  unsigned i;
+
+  if(magic_init_done || !_magic_enabled) {
+     return;
+  }
+
+  /* Initialize magic data structures first. */
+  magic_data_init();
+
+  /* Initialize asr support. */
+  magic_asr_init();
+
+  /* Initialize eval support. */
+  magic_eval_init();
+
+  /* Initialize magic obdsentries. */
+  memset(_magic_obdsentries, 0, MAGIC_MAX_OBDSENTRIES * sizeof(struct _magic_obdsentry));
+
+  /* Initialize memory pool descriptors. */
+  for (i = 0; i < MAGIC_MAX_MEMPOOLS; i++) {
+      sprintf(_magic_mpdescs[i].name, "%s%d%s", MAGIC_MEMPOOL_NAME_PREFIX, i, MAGIC_ALLOC_NAME_SUFFIX);
+  }
+
+  /* Initialize special types. */
+  magic_types_init();
+
+  /* Initialize magic ranges. */
+  magic_ranges_init();
+
+  /* Perform stack-related initialization. */
+  magic_stack_init();
+
+#if MAGIC_MEM_USAGE_OUTPUT_CTL
+   /* Initialize CPU frequency - used for timestamp logging. */
+   magic_cycles_per_ns = util_time_get_cycles_per_ns(1);
+#endif
+
+  /* Checks. */
+  assert(magic_check_sentries() && "Bad sentries!");
+  assert(magic_check_dsentries_safe() && "Bad dsentries!");
+
+  /* All done. */
+  magic_init_done = 1;
+}
+
+/*===========================================================================*
+ *                          magic_do_check_dfunction                         *
+ *===========================================================================*/
+PRIVATE INLINE int magic_do_check_dfunction(struct _magic_dfunction *dfunction, int flags)
+{
+    struct _magic_function *function;
+    int is_mnum_ok, is_flags_ok, is_prev_ok, is_next_ok;
+    assert(dfunction && "NULL dfunction found!");
+    function = MAGIC_DFUNCTION_TO_FUNCTION(dfunction);
+    assert(function && "NULL function found!");
+    is_mnum_ok = MAGIC_DFUNCTION_MNUM_OK(dfunction);
+    if(!is_mnum_ok) {
+        return FALSE;
+    }
+    is_flags_ok = ((function->flags & flags) == flags) && (function->flags & MAGIC_STATE_DYNAMIC) && (MAGIC_STATE_REGION(function) & MAGIC_STATE_TEXT);
+    is_prev_ok = (dfunction->prev ? dfunction->prev->next && dfunction->prev->next == dfunction : dfunction == _magic_first_dfunction);
+    is_next_ok = (dfunction->next ? dfunction->next->prev && dfunction->next->prev == dfunction : dfunction == _magic_last_dfunction);
+    if(!is_flags_ok || !is_prev_ok || !is_next_ok) {
+        _magic_printf("magic_do_check_dfunction: bad dfunction, checks: %d %d %d\n", is_flags_ok, is_prev_ok, is_next_ok);
+        MAGIC_DFUNCTION_PRINT(dfunction, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/*===========================================================================*
+ *                            magic_check_dfunction                          *
+ *===========================================================================*/
+PUBLIC int magic_check_dfunction(struct _magic_dfunction *dfunction, int flags)
+{
+    int check;
+    check = magic_do_check_dfunction(dfunction, flags);
+    if(!check) {
+        return FALSE;
+    }
+
+#if MAGIC_CHECK_LEVEL == 2
+    check = magic_check_dfunctions();
+    if(!check) {
+        _magic_printf("magic_check_dfunction: bad other dfunction\n");
+        return FALSE;
+    }
+#endif
+
+    return TRUE;
+}
+
+/*===========================================================================*
+ *                          magic_check_dfunctions                           *
+ *===========================================================================*/
+PUBLIC int magic_check_dfunctions()
+{
+    int magic_dfunctions_found = 0;
+    struct _magic_dfunction* dfunction = NULL;
+    struct _magic_function* function = NULL;
+    int ret, check = TRUE;
+
+    MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
+        ret = magic_do_check_dfunction(dfunction, 0);
+        if(ret == FALSE) {
+            check = FALSE;
+        }
+        magic_dfunctions_found++;
+    );
+    if(magic_dfunctions_found != _magic_dfunctions_num) {
+        _magic_printf("magic_check_dfunctions: magic_dfunctions_found=%d != _magic_dfunctions_num%d\n", magic_dfunctions_found, _magic_dfunctions_num);
+        check = FALSE;
+    }
+    if(dfunction != _magic_last_dfunction) {
+        _magic_printf("magic_check_dfunctions: dfunction=0x%08x != _magic_last_dfunction=0x%08x\n", dfunction, _magic_last_dfunction);
+        check = FALSE;
+    }
+    return check;
+}
+
+/*===========================================================================*
+ *                       magic_check_dfunctions_safe                         *
+ *===========================================================================*/
+PUBLIC int magic_check_dfunctions_safe()
+{
+    int ret;
+    MAGIC_DFUNCTION_LOCK();
+    ret = magic_check_dfunctions();
+    MAGIC_DFUNCTION_UNLOCK();
+    return ret;
+}
+
+/*===========================================================================*
+ *                         magic_print_dfunction                             *
+ *===========================================================================*/
+PUBLIC void magic_print_dfunction(struct _magic_dfunction *dfunction)
+{
+    MAGIC_DFUNCTION_PRINT(dfunction, MAGIC_EXPAND_TYPE_STR);
+}
+
+/*===========================================================================*
+ *                         magic_print_dfunctions                            *
+ *===========================================================================*/
+PUBLIC void magic_print_dfunctions()
+{
+    int magic_dfunctions_found = 0;
+    struct _magic_dfunction* dfunction;
+    struct _magic_function* function;
+
+    _magic_printf("magic_print_dfunctions: Printing %d functions\n", _magic_dfunctions_num);
+    MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
+        MAGIC_DFUNCTION_PRINT(dfunction, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+        magic_dfunctions_found++;
+    );
+    if(magic_dfunctions_found != _magic_dfunctions_num) {
+        _magic_printf("magic_print_dfunctions: magic_dfunctions_found=%d != _magic_dfunctions_num%d\n", magic_dfunctions_found, _magic_dfunctions_num);
+    }
+}
+
+/*===========================================================================*
+ *                      magic_print_dfunctions_safe                          *
+ *===========================================================================*/
+PUBLIC void magic_print_dfunctions_safe()
+{
+    MAGIC_DFUNCTION_LOCK();
+    magic_print_dfunctions();
+    MAGIC_DFUNCTION_UNLOCK();
+}
+
+/*===========================================================================*
+ *                             magic_copy_dfunction                          *
+ *===========================================================================*/
+PUBLIC void magic_copy_dfunction(struct _magic_dfunction *dfunction,
+    struct _magic_dfunction *dst_dfunction)
+{
+    /* Raw copy. */
+    memcpy(dst_dfunction, dfunction, sizeof(struct _magic_dfunction));
+}
+
+/*===========================================================================*
+ *                          magic_print_dsindex                              *
+ *===========================================================================*/
+PUBLIC void magic_print_dsindex(struct _magic_dsindex *dsindex)
+{
+    MAGIC_DSINDEX_PRINT(dsindex, MAGIC_EXPAND_TYPE_STR);
+}
+
+/*===========================================================================*
+ *                         magic_print_dsindexes                             *
+ *===========================================================================*/
+PUBLIC void magic_print_dsindexes()
+{
+    int i;
+    struct _magic_dsindex* dsindex;
+
+    _magic_printf("magic_print_dsindexes: Printing %d indexes\n", _magic_dsindexes_num);
+    for(i=0;i<_magic_dsindexes_num;i++) {
+        dsindex = &_magic_dsindexes[i];
+        MAGIC_DSINDEX_PRINT(dsindex, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+    }
+}
+
+/*===========================================================================*
+ *                           magic_do_check_dsentry                          *
+ *===========================================================================*/
+PRIVATE INLINE int magic_do_check_dsentry(struct _magic_dsentry *dsentry, int flags)
+{
+    struct _magic_sentry *sentry;
+    int is_mnum_ok, is_mstate_ok, is_flags_ok;
+    assert(dsentry && "NULL dsentry found!");
+    sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+    assert(sentry && "NULL sentry found!");
+    is_mnum_ok = MAGIC_DSENTRY_MNUM_OK(dsentry);
+    if(!is_mnum_ok) {
+        _magic_printf("magic_do_check_dsentry: bad ~mnum %08x\n", ~(dsentry->magic_number));
+        return FALSE;
+    }
+    is_mstate_ok = MAGIC_DSENTRY_MSTATE_OK(dsentry);
+    is_flags_ok = ((sentry->flags & flags) == flags) && (sentry->flags & MAGIC_STATE_DYNAMIC) && MAGIC_STATE_REGION(sentry);
+    if(!is_mstate_ok || !is_flags_ok) {
+        _magic_printf("magic_do_check_dsentry: bad dsentry, checks: %d %d\n", is_mstate_ok, is_flags_ok);
+        MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/*===========================================================================*
+ *                             magic_check_dsentry                           *
+ *===========================================================================*/
+PUBLIC int magic_check_dsentry(struct _magic_dsentry *dsentry, int flags)
+{
+#if MAGIC_CHECK_LEVEL >= 1
+    int check;
+    check = magic_do_check_dsentry(dsentry, flags);
+    if(!check) {
+        return FALSE;
+    }
+#endif
+
+#if MAGIC_CHECK_LEVEL == 2
+    check = magic_check_dsentries();
+    if(!check) {
+        _magic_printf("magic_check_dsentry: bad other dsentry\n");
+        return FALSE;
+    }
+#endif
+
+    return TRUE;
+}
+
+/*===========================================================================*
+ *                          magic_check_dsentries                            *
+ *===========================================================================*/
+PUBLIC int magic_check_dsentries()
+{
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry* sentry;
+    int ret, check = TRUE;
+
+    MAGIC_DSENTRY_NESTED_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+        ret = magic_do_check_dsentry(dsentry, 0);
+        if(ret == FALSE) {
+            check = FALSE;
+        }
+    );
+    return check;
+}
+
+/*===========================================================================*
+ *                       magic_check_dsentries_safe                          *
+ *===========================================================================*/
+PUBLIC int magic_check_dsentries_safe()
+{
+    int ret;
+    MAGIC_DSENTRY_LOCK();
+    ret = magic_check_dsentries();
+    MAGIC_DSENTRY_UNLOCK();
+    return ret;
+}
+
+/*===========================================================================*
+ *                          magic_print_dsentry                              *
+ *===========================================================================*/
+PUBLIC void magic_print_dsentry(struct _magic_dsentry *dsentry)
+{
+    MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
+}
+
+/*===========================================================================*
+ *                         magic_print_dsentries                             *
+ *===========================================================================*/
+PUBLIC void magic_print_dsentries()
+{
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry* sentry;
+    int magic_dsentries_num = 0;
+
+    _magic_printf("magic_print_dsentries: Printing entries\n");
+    MAGIC_DSENTRY_NESTED_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+        MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+        magic_dsentries_num++;
+    );
+    _magic_printf("magic_print_dsentries: %d entries found\n", magic_dsentries_num);
+}
+
+/*===========================================================================*
+ *                       magic_print_dsentries_safe                          *
+ *===========================================================================*/
+PUBLIC void magic_print_dsentries_safe()
+{
+    MAGIC_DSENTRY_LOCK();
+    magic_print_dsentries();
+    MAGIC_DSENTRY_UNLOCK();
+}
+
+/*===========================================================================*
+ *                             magic_copy_dsentry                            *
+ *===========================================================================*/
+PUBLIC void magic_copy_dsentry(struct _magic_dsentry *dsentry,
+    struct _magic_dsentry *dst_dsentry)
+{
+    struct _magic_sentry *sentry;
+
+    /* Raw copy. */
+    memcpy(dst_dsentry, dsentry, sizeof(struct _magic_dsentry));
+
+    /* Adjust pointers. */
+    sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+    if(sentry->type == &dsentry->type) {
+        MAGIC_DSENTRY_TO_SENTRY(dst_dsentry)->type = &dst_dsentry->type;
+        if(sentry->type->contained_types == dsentry->type_array) {
+            MAGIC_DSENTRY_TO_SENTRY(dst_dsentry)->type->contained_types = dst_dsentry->type_array;
+        }
+    }
+}
+
+/*===========================================================================*
+ *                         magic_print_sodesc                                *
+ *===========================================================================*/
+PUBLIC void magic_print_sodesc(struct _magic_sodesc *sodesc)
+{
+    MAGIC_SODESC_PRINT(sodesc);
+}
+
+/*===========================================================================*
+ *                         magic_print_sodescs                               *
+ *===========================================================================*/
+PUBLIC void magic_print_sodescs()
+{
+    int magic_sodescs_found = 0;
+    struct _magic_sodesc* sodesc;
+
+    _magic_printf("magic_print_sodescs: Printing %d sodescs\n", _magic_sodescs_num);
+    MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc,
+        MAGIC_SODESC_PRINT(sodesc);
+        _magic_printf("\n");
+        magic_sodescs_found++;
+    );
+    if(magic_sodescs_found != _magic_sodescs_num) {
+        _magic_printf("magic_print_sodescs: magic_sodescs_found=%d != _magic_sodescs_num%d\n", magic_sodescs_found, _magic_sodescs_num);
+    }
+}
+
+/*===========================================================================*
+ *                         magic_print_dsodesc                               *
+ *===========================================================================*/
+PUBLIC void magic_print_dsodesc(struct _magic_dsodesc *dsodesc)
+{
+    MAGIC_DSODESC_PRINT(dsodesc);
+}
+
+/*===========================================================================*
+ *                         magic_print_dsodescs                              *
+ *===========================================================================*/
+PUBLIC void magic_print_dsodescs()
+{
+    int magic_dsodescs_found = 0;
+    struct _magic_dsodesc* dsodesc;
+
+    _magic_printf("magic_print_dsodescs: Printing %d dsodescs\n", _magic_dsodescs_num);
+    MAGIC_DSODESC_ITER(_magic_first_dsodesc, dsodesc,
+        MAGIC_DSODESC_PRINT(dsodesc);
+        _magic_printf("\n");
+        magic_dsodescs_found++;
+    );
+    if(magic_dsodescs_found != _magic_dsodescs_num) {
+        _magic_printf("magic_print_dsodescs: magic_dsodescs_found=%d != _magic_dsodescs_num%d\n", magic_dsodescs_found, _magic_dsodescs_num);
+    }
+}
+
+/*===========================================================================*
+ *                       magic_print_dsodescs_safe                           *
+ *===========================================================================*/
+PUBLIC void magic_print_dsodescs_safe()
+{
+    MAGIC_DSODESC_LOCK();
+    magic_print_dsodescs();
+    MAGIC_DSODESC_UNLOCK();
+}
+
+/*===========================================================================*
+ *                           magic_print_sections                            *
+ *===========================================================================*/
+PUBLIC void magic_print_sections(void)
+{
+    _magic_printf("magic_print_sections: data=[0x%08x;0x%08x], ro=[0x%08x;0x%08x], text=[0x%08x;0x%08x], st_data=[0x%08x;0x%08x], st_ro=[0x%08x;0x%08x], st_text=[0x%08x;0x%08x]",
+            (unsigned long) MAGIC_DATA_SECTION_START, (unsigned long) MAGIC_DATA_SECTION_END,
+            (unsigned long) MAGIC_DATA_RO_SECTION_START, (unsigned long) MAGIC_DATA_RO_SECTION_END,
+            (unsigned long) MAGIC_TEXT_SECTION_START, (unsigned long) MAGIC_TEXT_SECTION_END,
+            (unsigned long) MAGIC_ST_DATA_SECTION_START, (unsigned long) MAGIC_ST_DATA_SECTION_END,
+            (unsigned long) MAGIC_ST_DATA_RO_SECTION_START, (unsigned long) MAGIC_ST_DATA_RO_SECTION_END,
+            (unsigned long) MAGIC_ST_TEXT_SECTION_START, (unsigned long) MAGIC_ST_TEXT_SECTION_END);
+}
+
+/*===========================================================================*
+ *                   magic_mempool_sentry_lookup_by_addr                     *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry* magic_mempool_sentry_lookup_by_range(void *addr, struct _magic_dsentry *dsentry_buff)
+{
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry* sentry;
+    struct _magic_sentry* entry = NULL;
+    void *start_address, *end_address;
+
+    MAGIC_DSENTRY_LOCK();
+    MAGIC_DSENTRY_MEMPOOL_ALIVE_ITER(_magic_first_mempool_dsentry, prev_dsentry, dsentry, sentry,
+        start_address = sentry->address;
+        end_address = (void*) (((char*)sentry->address) + sentry->type->size - 1);
+        if(MAGIC_ADDR_IS_WITHIN(addr, start_address, end_address)) {
+            if(dsentry_buff) {
+                magic_copy_dsentry(dsentry, dsentry_buff);
+                entry = MAGIC_DSENTRY_TO_SENTRY(dsentry_buff);
+            }
+            else {
+                entry = sentry;
+            }
+            break;
+        }
+    );
+    MAGIC_DSENTRY_UNLOCK();
+
+    return entry;
+}
+
+/*===========================================================================*
+ *                   magic_dsindex_lookup_by_name                            *
+ *===========================================================================*/
+PUBLIC struct _magic_dsindex* magic_dsindex_lookup_by_name(char *parent_name,
+    char *name)
+{
+    int i;
+    struct _magic_dsindex* index = NULL;
+    assert(parent_name && name);
+
+    /* Scan all the indexes and return the one matching the provided names. */
+    for(i=0;i<_magic_dsindexes_num;i++) {
+        if(!strcmp(_magic_dsindexes[i].parent_name, parent_name)
+            && !strcmp(_magic_dsindexes[i].name, name)) {
+            index = &_magic_dsindexes[i];
+            break;
+        }
+    }
+
+    return index;
+}
+
+/*===========================================================================*
+ *                          magic_dsentry_prev_lookup                        *
+ *===========================================================================*/
+PUBLIC struct _magic_dsentry* magic_dsentry_prev_lookup(struct _magic_dsentry* dsentry)
+{
+    struct _magic_dsentry *prev_dsentry, *it_dsentry;
+    struct _magic_sentry *sentry;
+    int found = 0;
+
+#if MAGIC_DSENTRY_ALLOW_PREV
+    return dsentry->prev;
+#else
+    MAGIC_DSENTRY_ITER(_magic_first_dsentry, prev_dsentry, it_dsentry, sentry,
+        if(dsentry == it_dsentry) {
+            found = 1;
+            break;
+        }
+    );
+    if(!found) {
+        return (struct _magic_dsentry*) MAGIC_ENOPTR;
+    }
+    return prev_dsentry;
+#endif
+}
+
+/*===========================================================================*
+ *                      magic_mempool_dsentry_prev_lookup                    *
+ *===========================================================================*/
+PUBLIC struct _magic_dsentry* magic_mempool_dsentry_prev_lookup(struct _magic_dsentry* dsentry)
+{
+    struct _magic_dsentry *prev_dsentry, *it_dsentry;
+    struct _magic_sentry *sentry;
+    int found = 0;
+
+    MAGIC_DSENTRY_MEMPOOL_ITER(_magic_first_mempool_dsentry, prev_dsentry, it_dsentry, sentry,
+        if(dsentry == it_dsentry) {
+            found = 1;
+            break;
+        }
+    );
+    if(!found) {
+        return (struct _magic_dsentry*) MAGIC_ENOPTR;
+    }
+    return prev_dsentry;
+}
+
+/*===========================================================================*
+ *                         magic_function_lookup_by_id                       *
+ *===========================================================================*/
+PUBLIC struct _magic_function* magic_function_lookup_by_id(_magic_id_t id,
+    struct _magic_dfunction *dfunction_buff)
+{
+    struct _magic_function* entry = NULL;
+    struct _magic_function* function;
+    struct _magic_dfunction* dfunction;
+
+    if(id <= 0) {
+        return NULL;
+    }
+
+    /* O(1) ID lookup for functions. */
+#if MAGIC_LOOKUP_FUNCTION
+    if(id <= _magic_functions_num) {
+        return &_magic_functions[id - 1];
+    }
+#endif
+
+    /* O(N) ID lookup for dfunctions. */
+#if MAGIC_LOOKUP_DFUNCTION
+    MAGIC_DFUNCTION_LOCK();
+    MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
+        if(function->id == id) {
+            if(dfunction_buff) {
+                magic_copy_dfunction(dfunction, dfunction_buff);
+                entry = MAGIC_DFUNCTION_TO_FUNCTION(dfunction_buff);
+            }
+            else {
+                entry = function;
+            }
+            break;
+        }
+    );
+    MAGIC_DFUNCTION_UNLOCK();
+#endif
+
+    return entry;
+}
+
+/*===========================================================================*
+ *                        magic_function_lookup_by_addr                      *
+ *===========================================================================*/
+PUBLIC struct _magic_function* magic_function_lookup_by_addr(void *addr,
+    struct _magic_dfunction *dfunction_buff)
+{
+    int i;
+    struct _magic_function *entry = NULL;
+    struct _magic_function *function;
+    struct _magic_dfunction *dfunction;
+
+#if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH
+    if (magic_function_hash_head) {
+        return magic_function_lookup_by_addr_hash(addr, dfunction_buff);
+    }
+#endif
+
+    /* Scan all the entries and return the one matching the provided address. */
+#if MAGIC_LOOKUP_FUNCTION
+    if (MAGIC_ADDR_IS_IN_RANGE(addr, magic_function_range)) {
+        for (i = 0 ; i < _magic_functions_num ; i++) {
+            if (_magic_functions[i].address == addr) {
+                entry = &_magic_functions[i];
+                break;
+            }
+        }
+    }
+#endif
+
+#if MAGIC_LOOKUP_DFUNCTION
+    MAGIC_DFUNCTION_LOCK();
+    if(!MAGIC_ADDR_LOOKUP_USE_DFUNCTION_RANGES || magic_range_is_dfunction(addr)) {
+        MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
+            if(function->address == addr) {
+                if(dfunction_buff) {
+                    magic_copy_dfunction(dfunction, dfunction_buff);
+                    entry = MAGIC_DFUNCTION_TO_FUNCTION(dfunction_buff);
+                }
+                else {
+                    entry = function;
+                }
+                break;
+            }
+        );
+    }
+    MAGIC_DFUNCTION_UNLOCK();
+#endif
+
+    return entry;
+}
+
+/*===========================================================================*
+ *                       magic_function_lookup_by_name                       *
+ *===========================================================================*/
+PUBLIC struct _magic_function* magic_function_lookup_by_name(char *parent_name, char *name)
+{
+    int i;
+    struct _magic_function* entry = NULL;
+
+    /* Scan all the entries and return the one matching the provided name(s). */
+#if MAGIC_LOOKUP_FUNCTION
+    for (i = 0 ; i < _magic_functions_num ; i++) {
+        if (!strcmp(_magic_functions[i].name, name)) {
+            if (!parent_name || !strcmp(MAGIC_FUNCTION_PARENT(&_magic_functions[i]), parent_name)) {
+                entry = &_magic_functions[i];
+                break;
+            }
+        }
+    }
+#endif
+
+    return entry;
+}
+
+/*===========================================================================*
+ *                         magic_function_hash_insert                        *
+ *===========================================================================*/
+PRIVATE void magic_function_hash_insert(struct _magic_function_hash **head,
+    struct _magic_function_hash *elem)
+{
+    if (head != NULL) {
+        struct _magic_function_hash *tmp;
+        HASH_FIND_PTR(*head, &elem->key, tmp);
+        /* Skip inserting this function if an identical one already exists. */
+        if (tmp)
+            return;
+    }
+/*
+ * **** START UTHASH SPECIFIC DEFINITIONS ****
+ */
+#undef uthash_malloc
+#undef uthash_free
+#define uthash_malloc(size)             magic_function_hash_alloc(size)
+#define uthash_free(addr, size)         magic_function_hash_dealloc(addr, size)
+/*
+ * Since we have a limited buffer, we need to stop bucket expansion when
+ * reaching a certain limit.
+ */
+#undef uthash_expand_fyi
+#define uthash_expand_fyi(tbl)                                                 \
+    do {                                                                       \
+        if (tbl->num_buckets == MAGIC_FUNCTION_ADDR_EST_MAX_BUCKETS) {         \
+            _magic_printf("Warning! Function address hash maximum bucket "     \
+                "number reached! Consider increasing "                         \
+                "MAGIC_FUNCTION_ADDR_EST_MAX_BUCKETS, unless you are "         \
+                "comfortable with the current performance.\n");                \
+            tbl->noexpand = 1;                                                 \
+        }                                                                      \
+    } while(0);
+/*
+ * **** FINISH UTHASH SPECIFIC DEFINITIONS ****
+ */
+    HASH_ADD_PTR(*head, key, elem);
+/*
+ * **** START UTHASH DEFINITION REMOVAL ****
+ */
+#undef uthash_malloc
+#undef uthash_free
+#undef uthash_expand_fyi
+/*
+ * **** FINISH UTHASH DEFINITION REMOVAL ****
+ */
+}
+
+/*===========================================================================*
+ *                         magic_function_hash_build                         *
+ *===========================================================================*/
+PUBLIC void magic_function_hash_build(void *buff, size_t buff_size)
+{
+    /*
+     * XXX:
+     * Warning: this implementation is thread unsafe and also makes
+     * magic_function_lookup_by_addr thread unsafe!
+     */
+    int i;
+    struct _magic_dfunction *dfunction;
+    struct _magic_function *function;
+    struct _magic_function_hash *function_hash, *head;
+
+    assert(buff && buff_size > 0);
+    magic_function_hash_buff = buff;
+    magic_function_hash_buff_offset = 0;
+    magic_function_hash_buff_size = buff_size;
+
+    head = NULL;
+
+    /* Add all the functions to the hash. */
+#if MAGIC_LOOKUP_FUNCTION
+    for(i = 0 ; i < _magic_functions_num ; i++) {
+        function_hash = (struct _magic_function_hash *)
+            magic_function_hash_alloc(sizeof(struct _magic_function_hash));
+        function = &_magic_functions[i];
+        MAGIC_FUNCTION_TO_HASH_EL(function, function_hash);
+        magic_function_hash_insert(&head, function_hash);
+    }
+#endif
+
+    /* Add all the dfunctions to the hash. */
+#if MAGIC_LOOKUP_DFUNCTION
+    MAGIC_DFUNCTION_LOCK();
+    MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
+        function_hash = (struct _magic_function_hash *)
+            magic_function_hash_alloc(sizeof(struct _magic_function_hash));
+        MAGIC_DFUNCTION_TO_HASH_EL(dfunction, function, function_hash);
+        magic_function_hash_insert(&head, function_hash);
+    );
+    MAGIC_DFUNCTION_UNLOCK();
+#endif
+    magic_function_hash_head = (void *)head;
+    assert(magic_function_hash_head);
+}
+
+/*===========================================================================*
+ *                        magic_function_hash_destroy                        *
+ *===========================================================================*/
+PUBLIC void magic_function_hash_destroy(void)
+{
+    magic_function_hash_buff = NULL;
+    magic_function_hash_buff_offset = 0;
+    magic_function_hash_buff_size = 0;
+    magic_function_hash_head = NULL;
+}
+
+/*===========================================================================*
+ *                    magic_function_hash_estimate_buff_size                 *
+ *===========================================================================*/
+PUBLIC size_t magic_function_hash_estimate_buff_size(int functions_num)
+{
+    if (functions_num == 0) {
+        functions_num = _magic_dfunctions_num;
+        functions_num += _magic_functions_num;
+    }
+
+    return (functions_num * sizeof(struct _magic_function_hash)) +
+        MAGIC_FUNCTION_ADDR_HASH_OVERHEAD;
+}
+
+/*===========================================================================*
+ *                           magic_function_hash_alloc                       *
+ *===========================================================================*/
+PUBLIC void* magic_function_hash_alloc(size_t size)
+{
+    void *addr;
+
+    assert(magic_function_hash_buff);
+    assert(magic_function_hash_buff_offset + size <=
+        magic_function_hash_buff_size);
+
+    addr = (char*) magic_function_hash_buff + magic_function_hash_buff_offset;
+    magic_function_hash_buff_offset += size;
+
+    return addr;
+}
+
+/*===========================================================================*
+ *                          magic_function_hash_dealloc                      *
+ *===========================================================================*/
+PUBLIC void magic_function_hash_dealloc(UNUSED(void *object), UNUSED(size_t sz))
+{
+    return;
+}
+
+/*===========================================================================*
+ *                      magic_function_lookup_by_addr_hash                   *
+ *===========================================================================*/
+PUBLIC struct _magic_function *magic_function_lookup_by_addr_hash(
+    void *addr, struct _magic_dfunction *dfunction_buff)
+{
+    /*
+     * Warning: this implementation is thread unsafe!
+     */
+    struct _magic_function_hash *res, *head;
+    head = (struct _magic_function_hash *) magic_function_hash_head;
+
+    HASH_FIND_PTR(head, &addr, res);
+    if (res == NULL)
+        return NULL;
+
+    if (MAGIC_STATE_FLAG(res->function, MAGIC_STATE_DYNAMIC) &&
+        dfunction_buff != NULL) {
+        magic_copy_dfunction(MAGIC_DFUNCTION_FROM_FUNCTION(res->function),
+            dfunction_buff);
+    }
+
+    return res->function;
+}
+
+/*===========================================================================*
+ *                         magic_type_lookup_by_name                         *
+ *===========================================================================*/
+PUBLIC struct _magic_type* magic_type_lookup_by_name(char *name)
+{
+    int i, j;
+    struct _magic_type* entry = NULL;
+
+    /* Scan all the entries and return the one matching the provided name. */
+#if MAGIC_LOOKUP_TYPE
+    for (i = 0 ; i < _magic_types_num ; i++) {
+        if (!strcmp(_magic_types[i].name, name)) {
+            entry = &_magic_types[i];
+            break;
+        }
+        if (_magic_types[i].names) {
+            for (j = 0 ; j < _magic_types[i].num_names ; j++) {
+                if (!strcmp(_magic_types[i].names[j], name)) {
+                    entry = &_magic_types[i];
+                    break;
+                }
+            }
+            if (entry) {
+                break;
+            }
+        }
+    }
+#endif
+
+    return entry;
+}
+
+/*===========================================================================*
+ *                      magic_dsodesc_lookup_by_handle                       *
+ *===========================================================================*/
+PUBLIC struct _magic_dsodesc* magic_dsodesc_lookup_by_handle(void *handle)
+{
+    struct _magic_dsodesc* desc = NULL;
+    struct _magic_dsodesc* dsodesc;
+
+    /*
+     * Scan all the descriptors and return the one matching the provided handle.
+     * Note that there is no locking here. The caller has to explicitely call
+     * MAGIC_DSODESC_LOCK/UNLOCK before/after invoking this function.
+     */
+    MAGIC_DSODESC_ITER(_magic_first_dsodesc, dsodesc,
+        if(dsodesc->handle == handle) {
+            desc = dsodesc;
+            break;
+        }
+    );
+
+    return desc;
+}
+
+/*===========================================================================*
+ *                         magic_print_function                              *
+ *===========================================================================*/
+PUBLIC void magic_print_function(struct _magic_function *function)
+{
+    MAGIC_FUNCTION_PRINT(function, MAGIC_EXPAND_TYPE_STR);
+}
+
+/*===========================================================================*
+ *                         magic_print_functions                             *
+ *===========================================================================*/
+PUBLIC void magic_print_functions()
+{
+    int i;
+    struct _magic_function* function;
+
+    _magic_printf("magic_print_functions: Printing %d entries\n", _magic_functions_num);
+    for(i=0;i<_magic_functions_num;i++) {
+        function = &_magic_functions[i];
+        MAGIC_FUNCTION_PRINT(function, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+    }
+}
+
+/*===========================================================================*
+ *                           magic_print_type                                *
+ *===========================================================================*/
+PUBLIC void magic_print_type(const struct _magic_type* type)
+{
+    MAGIC_TYPE_PRINT(type, MAGIC_EXPAND_TYPE_STR);
+}
+
+/*===========================================================================*
+ *                           magic_print_types                               *
+ *===========================================================================*/
+PUBLIC void magic_print_types()
+{
+    int i;
+    struct _magic_type* type;
+
+    _magic_printf("magic_print_types: Printing %d types\n", _magic_types_num);
+    for(i=0;i<_magic_types_num;i++) {
+        type = &_magic_types[i];
+        MAGIC_TYPE_PRINT(type, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+    }
+}
+
+/*===========================================================================*
+ *                      magic_type_str_set_print_style                       *
+ *===========================================================================*/
+PUBLIC void magic_type_str_set_print_style(const int style)
+{
+    magic_type_str_print_style = style;
+}
+
+/*===========================================================================*
+ *                      magic_type_str_get_print_style                       *
+ *===========================================================================*/
+PUBLIC int magic_type_str_get_print_style()
+{
+    return magic_type_str_print_style;
+}
+
+/*===========================================================================*
+ *                       magic_type_get_nesting_level                        *
+ *===========================================================================*/
+PRIVATE INLINE int magic_type_get_nesting_level(const struct _magic_type* type,
+    int level)
+{
+    int i;
+    int nesting_level = -1;
+
+    for(i=0;i<level;i++) {
+        if(magic_nested_types[i] == type) {
+            nesting_level = i;
+            break;
+        }
+    }
+
+    return nesting_level;
+}
+
+/*===========================================================================*
+ *                            magic_type_str_print                           *
+ *===========================================================================*/
+PUBLIC void magic_type_str_print(const struct _magic_type* type)
+{
+    int num_contained_types;
+    int is_empty_str = !type->type_str || !strcmp(type->type_str, "");
+    int type_has_name = type->name && strcmp(type->name, "");
+    int print_multi_names = (magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_MULTI_NAMES) && MAGIC_TYPE_HAS_MULTI_NAMES(type);
+    int print_ptr_name = (magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_MULTI_NAMES) && !MAGIC_TYPE_HAS_MULTI_NAMES(type) && type_has_name;
+    assert(magic_level < MAGIC_MAX_RECURSIVE_TYPES);
+
+    if(magic_level == 0) {
+        magic_counter = 0;
+    }
+    else if(magic_counter >= MAGIC_TYPE_STR_PRINT_MAX) {
+        _magic_printf("%%");
+        return;
+    }
+    else if(magic_level >= MAGIC_TYPE_STR_PRINT_MAX_LEVEL) {
+        _magic_printf("%%");
+        return;
+    }
+
+    if(MAGIC_TYPE_STR_PRINT_DEBUG) {
+        _magic_printf("Entering level %d...\n", magic_level);
+    }
+
+    if(type->type_id == MAGIC_TYPE_OPAQUE) {
+        _magic_printf("opaque");
+        magic_counter += strlen("opaque");
+        return;
+    }
+
+    num_contained_types = MAGIC_TYPE_NUM_CONTAINED_TYPES(type);
+    if(num_contained_types == 0) {
+        assert(!is_empty_str);
+        if((magic_type_str_print_style & (MAGIC_TYPE_STR_PRINT_LLVM_TYPES|MAGIC_TYPE_STR_PRINT_SOURCE_TYPES)) == (MAGIC_TYPE_STR_PRINT_LLVM_TYPES|MAGIC_TYPE_STR_PRINT_SOURCE_TYPES)) {
+            if(print_multi_names) {
+                _magic_printf("%s/", type->type_str);
+                magic_type_names_print(type);
+                magic_counter += strlen(type->type_str)+1+strlen(type->name)*type->num_names;
+            }
+            else {
+                _magic_printf("%s/%s", type->type_str, type->name);
+                magic_counter += strlen(type->type_str)+1+strlen(type->name);
+            }
+        }
+        else if(magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_LLVM_TYPES) {
+            _magic_printf(type->type_str);
+            magic_counter += strlen(type->type_str);
+        }
+        else if(magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_SOURCE_TYPES) {
+            if(print_multi_names) {
+                magic_type_names_print(type);
+                magic_counter += strlen(type->name)*type->num_names;
+            }
+            else {
+                _magic_printf(type->name);
+                magic_counter += strlen(type->name);
+            }
+        }
+        return;
+    }
+
+    if(type->type_id == MAGIC_TYPE_POINTER) {
+        int nesting_level = magic_type_get_nesting_level(type, magic_level);
+        if(nesting_level >= 0) {
+            _magic_printf("\\%d", magic_level - nesting_level);
+            magic_counter += 2;
+            return;
+        }
+    }
+
+    magic_nested_types[magic_level] = type;
+    magic_level++;
+    if(type->type_id == MAGIC_TYPE_POINTER) {
+        magic_type_str_print(type->contained_types[0]);
+        _magic_printf("*");
+        magic_counter += 1;
+        if(print_multi_names) {
+            _magic_printf("|");
+            magic_type_names_print(type);
+            magic_counter += 1+strlen(type->name)*type->num_names;
+        }
+        else if(print_ptr_name) {
+            _magic_printf("|");
+            _magic_printf("%s", type->name);
+            magic_counter += 1+strlen(type->name);
+        }
+    }
+    else if(type->type_id == MAGIC_TYPE_ARRAY || type->type_id == MAGIC_TYPE_VECTOR) {
+        int num_elements = type->num_child_types;
+        char start_sep = type->type_id == MAGIC_TYPE_ARRAY ? '[' : '<';
+        char end_sep = type->type_id == MAGIC_TYPE_ARRAY ? ']' : '>';
+        _magic_printf("%c", start_sep);
+        magic_counter += 1;
+        if(MAGIC_TYPE_FLAG(type, MAGIC_TYPE_VARSIZE)) {
+            _magic_printf(" (V) ");
+            magic_counter += 5;
+        }
+        if(num_elements) {
+            _magic_printf("%d x ", num_elements);
+            magic_counter += 5;
+        }
+        magic_type_str_print(type->contained_types[0]);
+        _magic_printf("%c", end_sep);
+        magic_counter += 1;
+    }
+    else if(type->type_id == MAGIC_TYPE_STRUCT || type->type_id == MAGIC_TYPE_UNION) {
+        int i;
+        int skip_struct = type->type_id == MAGIC_TYPE_STRUCT && (magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_SKIP_STRUCTS);
+        int skip_union = type->type_id == MAGIC_TYPE_UNION && (magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_SKIP_UNIONS);
+        _magic_printf("{ ");
+        magic_counter += 2;
+        if(type->type_id == MAGIC_TYPE_UNION) {
+            _magic_printf("(U) ");
+            magic_counter += 4;
+        }
+        if(print_multi_names) {
+            _magic_printf("$");
+            magic_type_names_print(type);
+            _magic_printf(" ");
+            magic_counter += 2 + strlen(type->name)*type->num_names;
+        }
+        else {
+            _magic_printf("$%s ", strcmp(type->name, "") ? type->name : "ANONYMOUS");
+            magic_counter += 2 + strlen(strcmp(type->name, "") ? type->name : "ANONYMOUS");
+        }
+        assert(type->member_names);
+        if(!skip_struct && !skip_union) {
+            for(i=0;i<num_contained_types;i++) {
+                if(i > 0) {
+                    _magic_printf(", ");
+                    magic_counter += 2;
+                }
+                if((magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_MEMBER_NAMES)
+                    && (!MAGIC_TYPE_STR_PRINT_MAX || magic_counter < MAGIC_TYPE_STR_PRINT_MAX)) {
+                    assert(type->member_names[i] && strcmp(type->member_names[i], "") && "Invalid member name!");
+                    _magic_printf("%s ", type->member_names[i]);
+                    magic_counter += strlen(type->member_names[i])+1;
+                }
+                magic_type_str_print(type->contained_types[i]);
+            }
+        }
+        _magic_printf(" }");
+        magic_counter += 2;
+   }
+   else if(type->type_id == MAGIC_TYPE_FUNCTION) {
+       int i;
+       assert(num_contained_types > 0);
+       magic_type_str_print(type->contained_types[0]);
+       num_contained_types--;
+       _magic_printf(" (");
+       magic_counter += 2;
+       for(i=0;i<num_contained_types;i++) {
+           if(i > 0) {
+               _magic_printf(", ");
+               magic_counter += 2;
+           }
+           magic_type_str_print(type->contained_types[i+1]);
+       }
+       _magic_printf(")");
+       magic_counter += 1;
+   }
+   else {
+       _magic_printf("???[id=%d,child_types=%d,size=%zu]", type->type_id, type->num_child_types, type->size);
+       magic_counter += 30;
+   }
+   magic_level--;
+   if(MAGIC_TYPE_STR_PRINT_DEBUG) {
+       _magic_printf("Exiting level %d...\n", magic_level);
+   }
+}
+
+/*===========================================================================*
+ *                         magic_type_values_print                           *
+ *===========================================================================*/
+PUBLIC void magic_type_values_print(const struct _magic_type* type)
+{
+    int i=0;
+
+    if(!MAGIC_TYPE_HAS_VALUE_SET(type)) {
+        return;
+    }
+    while(MAGIC_TYPE_HAS_VALUE(type, i)) {
+        int value = MAGIC_TYPE_VALUE(type, i);
+        _magic_printf("%s%d", (i==0 ? "" : ", "), value);
+        i++;
+    }
+}
+
+/*===========================================================================*
+ *                         magic_type_names_print                            *
+ *===========================================================================*/
+PUBLIC void magic_type_names_print(const struct _magic_type* type)
+{
+    int i;
+
+    for(i=0;i<type->num_names;i++) {
+        _magic_printf("%s%s", (i==0 ? "" : "|"), type->names[i]);
+    }
+}
+
+/*===========================================================================*
+ *                       magic_type_comp_types_print                         *
+ *===========================================================================*/
+PUBLIC void magic_type_comp_types_print(const struct _magic_type* type,
+    int flags)
+{
+    int num;
+    int i=0;
+    const struct _magic_type* comp_type;
+
+    if(!MAGIC_TYPE_HAS_COMP_TYPES(type)) {
+        return;
+    }
+    MAGIC_TYPE_NUM_COMP_TYPES(type, &num);
+    _magic_printf("#%d", num);
+    if(flags & MAGIC_SKIP_COMP_TYPES) {
+        return;
+    }
+    flags &= ~MAGIC_EXPAND_TYPE_STR;
+
+    MAGIC_TYPE_COMP_ITER(type, comp_type,
+        _magic_printf("%s%d=", (i==0 ? ": " : ", "), i+1);
+        MAGIC_TYPE_PRINT(comp_type, flags|MAGIC_SKIP_COMP_TYPES);
+        i++;
+    );
+}
+
+/*===========================================================================*
+ *                     magic_type_str_print_from_target                      *
+ *===========================================================================*/
+PUBLIC int magic_type_str_print_from_target(void* target)
+{
+    int printed_types=0;
+    int ret;
+    ret = magic_type_target_walk(target, NULL, NULL,
+        magic_type_str_print_cb, &printed_types);
+    if(ret < 0) {
+        return ret;
+    }
+    if(printed_types == 0) {
+        _magic_printf("BAD OFFSET");
+    }
+    return printed_types;
+}
+
+/*===========================================================================*
+ *                            magic_type_equals                              *
+ *===========================================================================*/
+PUBLIC int magic_type_equals(const struct _magic_type* type, const struct _magic_type* other_type)
+{
+    assert(magic_level < MAGIC_MAX_RECURSIVE_TYPES);
+
+    if(type == other_type) {
+        return TRUE;
+    }
+    if(type->type_id != other_type->type_id) {
+        return FALSE;
+    }
+    if((type->flags & MAGIC_TYPE_EXTERNAL) || (other_type->flags & MAGIC_TYPE_EXTERNAL)) {
+        int i, nesting_level;
+        if(type->num_child_types == other_type->num_child_types) {
+            int num_contained_types = MAGIC_TYPE_NUM_CONTAINED_TYPES(type);
+            if(num_contained_types == 0) {
+                return !strcmp(type->type_str, other_type->type_str);
+            }
+            nesting_level = magic_type_get_nesting_level(type, magic_level);
+            if(nesting_level >= 0) {
+                return (other_type == magic_nested_types2[nesting_level]);
+            }
+            magic_nested_types[magic_level] = type;
+            magic_nested_types2[magic_level] = other_type;
+            magic_level++;
+            for(i=0;i<num_contained_types;i++) {
+                if(magic_type_equals(type->contained_types[i], other_type->contained_types[i]) == FALSE) {
+                    magic_level--;
+                    return FALSE;
+                }
+            }
+            magic_level--;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/*===========================================================================*
+ *                           magic_type_compatible                           *
+ *===========================================================================*/
+PUBLIC int magic_type_compatible(const struct _magic_type* type, const struct _magic_type* other_type, int flags)
+{
+    int i, nesting_level, num_contained_types;
+    assert(magic_level < MAGIC_MAX_RECURSIVE_TYPES);
+
+    if(type == other_type) {
+        return TRUE;
+    }
+
+    if(type->type_id != other_type->type_id) {
+        return FALSE;
+    }
+
+    if(type->num_child_types != other_type->num_child_types) {
+        return FALSE;
+    }
+
+    if(flags & MAGIC_TYPE_COMPARE_FLAGS) {
+        if((type->flags & (~MAGIC_TYPE_IS_ROOT)) != (other_type->flags & (~MAGIC_TYPE_IS_ROOT))){
+            return FALSE;
+        }
+    }
+
+    if(flags & MAGIC_TYPE_COMPARE_VALUE_SET) {
+        if(MAGIC_TYPE_HAS_VALUE_SET(type) != MAGIC_TYPE_HAS_VALUE_SET(other_type)){
+            return FALSE;
+        }
+        if(MAGIC_TYPE_HAS_VALUE_SET(type)){
+            i=0;
+            while(MAGIC_TYPE_HAS_VALUE(type, i) && MAGIC_TYPE_HAS_VALUE(other_type, i)) {
+                if(MAGIC_TYPE_VALUE(type, i) != MAGIC_TYPE_VALUE(other_type, i)){
+                    /* a value is different */
+                    return FALSE;
+                }
+                i++;
+            }
+            if(MAGIC_TYPE_HAS_VALUE(type, i) || MAGIC_TYPE_HAS_VALUE(other_type, i)) {
+                return FALSE;
+            }
+        }
+    }
+
+    if(flags & MAGIC_TYPE_COMPARE_NAME) {
+        if(strcmp(type->name, other_type->name)){
+            return FALSE;
+        }
+    }
+
+    if(flags & MAGIC_TYPE_COMPARE_NAMES) {
+        if(type->num_names != other_type->num_names) {
+            return FALSE;
+        }
+        if(type->num_names > 1) {
+            for(i=0; i<type->num_names; i++){
+                if(strcmp(type->names[i], other_type->names[i])) {
+                    return FALSE;
+                }
+            }
+        }
+    }
+
+    num_contained_types = MAGIC_TYPE_NUM_CONTAINED_TYPES(type);
+    if(num_contained_types == 0) {
+        return type->size == other_type->size && !strcmp(type->type_str, other_type->type_str);
+    }
+
+    if(type->type_id == MAGIC_TYPE_STRUCT) {
+        if(flags & MAGIC_TYPE_COMPARE_MEMBER_NAMES) {
+            for(i=0; i<type->num_child_types; i++){
+                if(strcmp(type->member_names[i], other_type->member_names[i])) {
+                    return FALSE;
+                }
+            }
+        }
+        if(flags & MAGIC_TYPE_COMPARE_MEMBER_OFFSETS) {
+            for(i=0; i<type->num_child_types; i++){
+                if(type->member_offsets[i] != other_type->member_offsets[i]) {
+                    return FALSE;
+                }
+            }
+        }
+    }
+
+    nesting_level = magic_type_get_nesting_level(type, magic_level);
+    if(nesting_level >= 0) {
+        return (other_type == magic_nested_types2[nesting_level]);
+    }
+    magic_nested_types[magic_level] = type;
+    magic_nested_types2[magic_level] = other_type;
+    magic_level++;
+    for(i=0;i<num_contained_types;i++) {
+        if(!magic_type_compatible(type->contained_types[i], other_type->contained_types[i], flags)) {
+            magic_level--;
+            return FALSE;
+        }
+    }
+    magic_level--;
+    return TRUE;
+}
+
+/*===========================================================================*
+ *                        magic_type_comp_compatible                         *
+ *===========================================================================*/
+PUBLIC int magic_type_comp_compatible(const struct _magic_type* type, const struct _magic_type* other_type)
+{
+    const struct _magic_type *comp_type;
+
+    MAGIC_TYPE_COMP_ITER(type, comp_type,
+        if(magic_type_compatible(comp_type, other_type, 0)) {
+             return TRUE;
+        }
+    );
+
+    return FALSE;
+}
+
+/*===========================================================================*
+ *                          magic_type_ptr_is_text                           *
+ *===========================================================================*/
+PUBLIC int magic_type_ptr_is_text(const struct _magic_type* ptr_type)
+{
+    const struct _magic_type *comp_type;
+
+    assert(ptr_type->type_id == MAGIC_TYPE_POINTER);
+    if(ptr_type->contained_types[0]->type_id == MAGIC_TYPE_FUNCTION
+        || MAGIC_TYPE_IS_VOID(ptr_type->contained_types[0])) {
+        return TRUE;
+    }
+
+    MAGIC_TYPE_COMP_ITER(ptr_type, comp_type,
+        if(comp_type->type_id == MAGIC_TYPE_FUNCTION
+            || MAGIC_TYPE_IS_VOID(comp_type)) {
+            return TRUE;
+        }
+    );
+
+    return FALSE;
+}
+
+/*===========================================================================*
+ *                          magic_type_ptr_is_data                           *
+ *===========================================================================*/
+PUBLIC int magic_type_ptr_is_data(const struct _magic_type* ptr_type)
+{
+    const struct _magic_type *comp_type;
+
+    assert(ptr_type->type_id == MAGIC_TYPE_POINTER);
+    if(ptr_type->contained_types[0]->type_id != MAGIC_TYPE_FUNCTION) {
+        return TRUE;
+    }
+
+    MAGIC_TYPE_COMP_ITER(ptr_type, comp_type,
+        if(comp_type->type_id != MAGIC_TYPE_FUNCTION) {
+            return TRUE;
+        }
+    );
+
+    return FALSE;
+}
+
+/*===========================================================================*
+ *                    magic_type_alloc_needs_varsized_array                  *
+ *===========================================================================*/
+PUBLIC int magic_type_alloc_needs_varsized_array(const struct _magic_type* type,
+    size_t alloc_size, int *num_elements)
+{
+    /* See if this type needs a var-sized array for the given allocation size */
+    const struct _magic_type *array_type, *array_el_type;
+    size_t array_offset, array_size;
+    if(!MAGIC_TYPE_FLAG(type, MAGIC_TYPE_VARSIZE)) {
+        return FALSE;
+    }
+    assert(type->type_id == MAGIC_TYPE_STRUCT);
+
+    if(alloc_size <= type->size || type->num_child_types == 0) {
+        return FALSE;
+    }
+    array_type = type->contained_types[type->num_child_types-1];
+    if(array_type->type_id != MAGIC_TYPE_ARRAY) {
+        return FALSE;
+    }
+    array_el_type = array_type->contained_types[0];
+    array_offset = type->member_offsets[type->num_child_types-1]+array_type->num_child_types*array_el_type->size;
+    array_size = alloc_size - array_offset;
+    if(array_size == 0 || array_size % array_el_type->size != 0) {
+        return FALSE;
+    }
+    if(num_elements) {
+        *num_elements = 1+array_size/array_el_type->size;
+    }
+
+    return TRUE;
+}
+
+/*===========================================================================*
+ *                     magic_type_alloc_get_varsized_array_size              *
+ *===========================================================================*/
+PUBLIC size_t magic_type_alloc_get_varsized_array_size(const struct _magic_type* type,
+    int num_elements)
+{
+    /* Get the allocation size from the number of elements of the varsized array. */
+    const struct _magic_type *array_type, *array_el_type;
+    size_t array_offset;
+    if(!MAGIC_TYPE_FLAG(type, MAGIC_TYPE_VARSIZE)) {
+        return 0;
+    }
+    assert(type->type_id == MAGIC_TYPE_STRUCT);
+
+    if(num_elements == 1) {
+        return type->size;
+    }
+    array_type = type->contained_types[type->num_child_types-1];
+    if(array_type->type_id != MAGIC_TYPE_ARRAY) {
+        return 0;
+    }
+    array_el_type = array_type->contained_types[0];
+    array_offset = type->member_offsets[type->num_child_types-1]+array_type->num_child_types*array_el_type->size;
+    return array_offset + array_el_type->size*(num_elements-1);
+}
+
+/*===========================================================================*
+ *                      magic_type_parse_varsized_array                      *
+ *===========================================================================*/
+PUBLIC void magic_type_parse_varsized_array(const struct _magic_type *type,
+    const struct _magic_type **sub_struct_type, const struct _magic_type **sub_array_type,
+    size_t *sub_array_offset, size_t *sub_array_size)
+{
+    /* Parse a var-sized array containing a variable-sized struct. */
+    const struct _magic_type *_sub_struct_type, *_sub_array_type, *_sub_array_el_type;
+    size_t _sub_array_offset, _sub_array_size;
+
+    assert(type->type_id == MAGIC_TYPE_ARRAY && MAGIC_TYPE_FLAG(type, MAGIC_TYPE_DYNAMIC));
+    _sub_struct_type = type->contained_types[0];
+    assert(magic_type_alloc_needs_varsized_array(_sub_struct_type, type->size, NULL));
+
+    _sub_array_type = _sub_struct_type->contained_types[_sub_struct_type->num_child_types-1];
+    _sub_array_el_type = _sub_array_type->contained_types[0];
+    _sub_array_offset = _sub_struct_type->member_offsets[_sub_struct_type->num_child_types-1]+_sub_array_type->num_child_types*_sub_array_el_type->size;
+    _sub_array_size = type->size - _sub_array_offset;
+
+    if(sub_struct_type) *sub_struct_type = _sub_struct_type;
+    if(sub_array_type) *sub_array_type = _sub_array_type;
+    if(sub_array_offset) *sub_array_offset = _sub_array_offset;
+    if(sub_array_size) *sub_array_size = _sub_array_size;
+}
+
+/*===========================================================================*
+ *                          magic_type_walk_flags                            *
+ *===========================================================================*/
+PUBLIC int magic_type_walk_flags(const struct _magic_type* parent_type,
+    unsigned parent_offset, int child_num,
+    const struct _magic_type* type, unsigned offset,
+    const unsigned min_offset, const unsigned max_offset,
+    const magic_type_walk_cb_t cb, void* cb_args, int flags) {
+    static THREAD_LOCAL int magic_depth = 0;
+    int ret, status, action;
+    ret = MAGIC_TYPE_WALK_CONTINUE;
+
+    if(offset >= min_offset && offset <= max_offset) {
+         ret = cb(parent_type, parent_offset, child_num, type, offset, magic_depth, cb_args);
+    }
+    else if(offset > max_offset) {
+        ret = MAGIC_TYPE_WALK_STOP;
+    }
+    else if(offset+type->size <= min_offset) {
+        ret = MAGIC_TYPE_WALK_SKIP_PATH;
+    }
+
+    /* The status code returned to the caller is propagated directly from the
+     * callback only in case of ret<0 and ret == MAGIC_TYPE_WALK_STOP.
+     * In all the other cases, we return 0 the caller.
+     */
+    status = ret < 0 ? ret : 0;
+    action = ret < 0 ? MAGIC_TYPE_WALK_STOP : ret;
+    switch(action) {
+        case MAGIC_TYPE_WALK_STOP:
+            status = status ? status : MAGIC_TYPE_WALK_STOP;
+        break;
+        case MAGIC_TYPE_WALK_SKIP_PATH:
+            status = 0;
+        break;
+        case MAGIC_TYPE_WALK_CONTINUE:
+            if(!MAGIC_TYPE_IS_WALKABLE(type)) {
+                status = 0;
+            }
+            else {
+                int i, num_child_types, start;
+                num_child_types = type->num_child_types;
+                start = 0;
+                if(type->type_id == MAGIC_TYPE_ARRAY || type->type_id == MAGIC_TYPE_VECTOR) {
+                    if(!MAGIC_TYPE_FLAG(type, MAGIC_TYPE_VARSIZE) && offset < min_offset) {
+                        /* Skip irrelevant array iterations. */
+                        start = (min_offset-offset)/(type->contained_types[0]->size);
+                    }
+                }
+                for(i=start;i<num_child_types;i++) {
+                    const struct _magic_type *child_type;
+                    unsigned child_offset;
+                    magic_type_walk_step(type, i, &child_type, &child_offset, flags);
+                    magic_depth++;
+                    status = magic_type_walk_flags(type, offset, i, child_type, offset+child_offset, min_offset, max_offset, cb, cb_args, flags);
+                    magic_depth--;
+                    if(status < 0 || status == MAGIC_TYPE_WALK_STOP) {
+                        break;
+                    }
+                }
+            }
+        break;
+        default:
+            _magic_printf("magic_type_walk: unrecognized callback return code: %d, stopping type walk...\n", action);
+            status = MAGIC_TYPE_WALK_STOP;
+        break;
+    }
+    return status;
+}
+
+/*===========================================================================*
+ *                          magic_type_target_walk                           *
+ *===========================================================================*/
+PUBLIC int magic_type_target_walk(void *target,
+    struct _magic_dsentry **trg_dsentry, struct _magic_dfunction **trg_dfunction,
+    const magic_type_walk_cb_t cb, void *cb_args)
+{
+    int ret;
+    struct _magic_sentry *sentry = NULL;
+    struct _magic_function *function = NULL;
+    sentry = magic_sentry_lookup_by_range(target, magic_reentrant ? &magic_dsentry_buff : NULL);
+    if (sentry == NULL) {
+        function = magic_function_lookup_by_addr(target, magic_reentrant ? &magic_dfunction_buff : NULL);
+        if (function == NULL) {
+            /* No known entry found. */
+            return MAGIC_ENOENT;
+        }
+        if (MAGIC_STATE_FLAG(function, MAGIC_STATE_ADDR_NOT_TAKEN)) {
+            /* A function has been found, but it was not supposed to be a target. */
+            return MAGIC_EBADENT;
+        }
+    }
+    else if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_ADDR_NOT_TAKEN)) {
+        /* An entry has been found, but it was not supposed to be a target. */
+        return MAGIC_EBADENT;
+    }
+    assert(sentry || function);
+    if (magic_reentrant) {
+        if (sentry) {
+            if (trg_dsentry) {
+                if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_DYNAMIC)) {
+                    magic_copy_dsentry(MAGIC_DSENTRY_FROM_SENTRY(sentry), *trg_dsentry);
+                }
+                else {
+                    memcpy(MAGIC_DSENTRY_TO_SENTRY(*trg_dsentry), sentry, sizeof(struct _magic_sentry));
+                }
+            }
+            if (trg_dfunction) {
+                *trg_dfunction = NULL;
+            }
+        }
+        else {
+            if (trg_dfunction) {
+                if (MAGIC_STATE_FLAG(function, MAGIC_STATE_DYNAMIC)) {
+                    magic_copy_dfunction(MAGIC_DFUNCTION_FROM_FUNCTION(function), *trg_dfunction);
+                }
+                else {
+                    memcpy(MAGIC_DFUNCTION_TO_FUNCTION(*trg_dfunction), function, sizeof(struct _magic_function));
+                }
+            }
+            if (trg_dsentry) {
+                *trg_dsentry = NULL;
+            }
+        }
+    } else {
+        /*
+         * Just return the pointer to the target object.
+         * NB!: Because the target objects can be static (i.e. sentries,
+         * functions), the user MUST first check the flag
+         * of the returned target element to see if it is a sentry
+         * or function. Otherwise, he might end up accessing invalid
+         * memory.
+         */
+        if (sentry) {
+            if (trg_dsentry) {
+                *trg_dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
+            }
+            if (trg_dfunction) {
+                *trg_dfunction = NULL;
+            }
+        }
+        else {
+            if (trg_dfunction) {
+                *trg_dfunction = MAGIC_DFUNCTION_FROM_FUNCTION(function);
+            }
+            if (trg_dsentry) {
+                *trg_dsentry = NULL;
+            }
+        }
+    }
+
+    if (sentry) {
+        ret = magic_type_walk_root_at_offset(sentry->type, (char *) target - (char *) sentry->address, cb, cb_args);
+    } else {
+        ret = magic_type_walk_root_at_offset(function->type, (char*) target - (char*) function->address, cb, cb_args);
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                      magic_type_walk_as_void_array                        *
+ *===========================================================================*/
+PUBLIC int magic_type_walk_as_void_array(const struct _magic_type* parent_type,
+    unsigned parent_offset, int child_num, const struct _magic_type* type,
+    unsigned offset, const unsigned min_offset, const unsigned max_offset,
+    const magic_type_walk_cb_t cb, void* cb_args)
+{
+    struct _magic_type void_array_type;
+    MAGIC_TYPE_VOID_ARRAY_GET_FROM_SIZE(&void_array_type, type->size);
+    return magic_type_walk(parent_type, parent_offset, child_num, &void_array_type,
+        offset, min_offset, max_offset, cb, cb_args);
+}
+
+/*===========================================================================*
+ *                     magic_type_walk_as_ptrint_array                       *
+ *===========================================================================*/
+PUBLIC int magic_type_walk_as_ptrint_array(const struct _magic_type* parent_type,
+    unsigned parent_offset, int child_num, const struct _magic_type* type, void* offset_addr,
+    unsigned offset, const unsigned min_offset, const unsigned max_offset,
+    const magic_type_walk_cb_t cb, void* cb_args)
+{
+    struct _magic_type ptrint_array_type;
+    unsigned type_size = type->size;
+    unsigned addr_diff = ((unsigned)offset_addr) % sizeof(void*);
+    if(addr_diff > 0) {
+        unsigned addr_off_by = sizeof(void*) - addr_diff;
+        if(type_size <= addr_off_by) {
+            return MAGIC_EBADWALK;
+        }
+        type_size -= addr_off_by;
+        offset_addr = (void*)((unsigned)offset_addr + addr_off_by);
+        offset += addr_off_by;
+    }
+    addr_diff = (((unsigned)offset_addr)+type_size) % sizeof(void*);
+    if(addr_diff > 0) {
+        unsigned addr_off_by = addr_diff;
+        if(type_size <= addr_off_by) {
+            return MAGIC_EBADWALK;
+        }
+        type_size -= addr_off_by;
+    }
+    MAGIC_TYPE_PTRINT_ARRAY_GET_FROM_SIZE(&ptrint_array_type, type_size);
+    return magic_type_walk(parent_type, parent_offset, child_num, &ptrint_array_type,
+        offset, min_offset, max_offset, cb, cb_args);
+}
+
+/*===========================================================================*
+ *                         magic_type_str_print_cb                           *
+ *===========================================================================*/
+PUBLIC int magic_type_str_print_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num,
+    const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
+{
+    int *printed_types = (int*) cb_args;
+    if(printed_types) (*printed_types)++;
+    magic_type_str_print(type);
+    _magic_printf("; ");
+    return MAGIC_TYPE_WALK_CONTINUE;
+}
+
+/*===========================================================================*
+ *                            magic_type_count_cb                            *
+ *===========================================================================*/
+PUBLIC int magic_type_count_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num,
+    const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
+{
+    int *type_counter = (int*) cb_args;
+    if(type_counter) (*type_counter)++;
+    return MAGIC_TYPE_WALK_CONTINUE;
+}
+
+/*===========================================================================*
+ *                         magic_type_child_offset_cb                        *
+ *===========================================================================*/
+PUBLIC int magic_type_child_offset_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num,
+    const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
+{
+    void **args_array = (void**) cb_args;
+    int *my_child_num = (int*) args_array[0];
+    unsigned *child_offset = (unsigned*) args_array[1];
+
+    if(!parent_type) {
+        return MAGIC_TYPE_WALK_CONTINUE;
+    }
+    if(child_num == *my_child_num) {
+        *child_offset = offset;
+        return MAGIC_TYPE_WALK_STOP;
+    }
+    return MAGIC_TYPE_WALK_SKIP_PATH;
+}
+
+/*===========================================================================*
+ *                            magic_type_walk_step                           *
+ *===========================================================================*/
+PUBLIC void magic_type_walk_step(const struct _magic_type *type,
+    int child_num, const struct _magic_type **child_type, unsigned *child_offset,
+    int walk_flags)
+{
+    int type_id;
+    struct _magic_type type_buff;
+    if(type->type_id == MAGIC_TYPE_UNION && (walk_flags & MAGIC_TYPE_WALK_UNIONS_AS_VOID)) {
+        MAGIC_TYPE_VOID_ARRAY_GET_FROM_SIZE(&type_buff, type->size);
+        type = &type_buff;
+    }
+    type_id = type->type_id;
+    if(type_id == MAGIC_TYPE_STRUCT || type_id == MAGIC_TYPE_UNION) {
+        *child_type = type->contained_types[child_num];
+        *child_offset = type->member_offsets[child_num];
+    }
+    else {
+        assert(type_id == MAGIC_TYPE_ARRAY || type_id == MAGIC_TYPE_VECTOR);
+        if(MAGIC_TYPE_FLAG(type, MAGIC_TYPE_VARSIZE) && child_num > 0) {
+            const struct _magic_type *sub_array_type, *sub_array_el_type;
+            size_t sub_array_offset;
+            magic_type_parse_varsized_array(type, NULL, &sub_array_type, &sub_array_offset, NULL);
+            sub_array_el_type = sub_array_type->contained_types[0];
+            *child_type = sub_array_el_type;
+            *child_offset = sub_array_offset + (child_num-1)*sub_array_el_type->size;
+        }
+        else {
+            *child_type = type->contained_types[0];
+            *child_offset = child_num*((*child_type)->size);
+        }
+    }
+}
+
+/*===========================================================================*
+ *                            magic_type_get_size                            *
+ *===========================================================================*/
+PUBLIC size_t magic_type_get_size(struct _magic_type *type, int flags)
+{
+    size_t size;
+    int i, num_contained_types;
+
+    size = sizeof(type->size) +
+           sizeof(type->num_child_types) + sizeof(type->contained_types) +
+           sizeof(type->member_offsets) + sizeof(type->type_id) + sizeof(type->flags);
+    num_contained_types = MAGIC_TYPE_NUM_CONTAINED_TYPES(type);
+
+    if(num_contained_types > 0) {
+        size += sizeof(*(type->contained_types))*num_contained_types;
+    }
+    if(type->type_id == MAGIC_TYPE_STRUCT) {
+        size += sizeof(*(type->member_offsets))*num_contained_types;
+        if(flags & MAGIC_SIZE_MEMBER_NAMES) {
+            size += sizeof(*(type->member_names))*num_contained_types;
+            for(i=0;i<num_contained_types;i++) {
+                size += strlen(type->member_names[i])+1;
+            }
+        }
+    }
+
+    if(flags & MAGIC_SIZE_VALUE_SET) {
+        if(MAGIC_TYPE_HAS_VALUE_SET(type)) {
+            int num;
+            MAGIC_TYPE_NUM_VALUES(type, &num);
+            size += sizeof(int)+(num+1);
+        }
+    }
+    if(flags & MAGIC_SIZE_TYPE_NAMES) {
+        size += sizeof(type->num_names) + sizeof(type->names) + sizeof(*(type->names))*(type->num_names);
+        for(i=0;i<type->num_names;i++) {
+            size += strlen(type->names[i])+1;
+        }
+    }
+    if(flags & MAGIC_SIZE_COMP_TYPES) {
+        if(MAGIC_TYPE_HAS_COMP_TYPES(type)) {
+            int num;
+            MAGIC_TYPE_NUM_COMP_TYPES(type, &num);
+            size += sizeof(*(type->compatible_types))*num;
+        }
+    }
+
+    return size;
+}
+
+/*===========================================================================*
+ *                            magic_types_get_size                           *
+ *===========================================================================*/
+PUBLIC size_t magic_types_get_size(int flags)
+{
+    size_t size;
+    int i;
+
+    size = 0;
+    for(i=0;i<_magic_types_num;i++) {
+        size += magic_type_get_size(&_magic_types[i], flags);
+    }
+
+    return size;
+}
+
+/*===========================================================================*
+ *                          magic_function_get_size                          *
+ *===========================================================================*/
+PUBLIC size_t magic_function_get_size(struct _magic_function *function, int flags)
+{
+    size_t size;
+
+    size = sizeof(function->type) + sizeof(function->flags) + sizeof(function->address);
+
+    if(flags & MAGIC_SIZE_NAMES) {
+        size += sizeof(function->name) + strlen(function->name)+1;
+    }
+
+    return size;
+}
+
+/*===========================================================================*
+ *                          magic_functions_get_size                         *
+ *===========================================================================*/
+PUBLIC size_t magic_functions_get_size(int flags)
+{
+    size_t size;
+    int i;
+
+    size = 0;
+    for(i=0;i<_magic_functions_num;i++) {
+        size += magic_function_get_size(&_magic_functions[i], flags);
+    }
+
+    return size;
+}
+
+/*===========================================================================*
+ *                         magic_dfunctions_get_size                         *
+ *===========================================================================*/
+PUBLIC size_t magic_dfunctions_get_size(int flags)
+{
+    size_t size;
+    struct _magic_dfunction* dfunction;
+    struct _magic_function* function;
+
+    size = 0;
+    MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
+        size += magic_function_get_size(function, flags);
+    );
+
+    return size;
+}
+
+/*===========================================================================*
+ *                           magic_sentry_get_size                           *
+ *===========================================================================*/
+PUBLIC size_t magic_sentry_get_size(struct _magic_sentry *sentry, int flags)
+{
+    size_t size;
+
+    size = sizeof(sentry->type) + sizeof(sentry->flags);
+
+    if(MAGIC_SENTRY_IS_DSENTRY(sentry)) {
+        struct _magic_dsentry *dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
+        if(flags & MAGIC_SIZE_DSENTRY_NAMES) {
+            size += sizeof(sentry->name) + strlen(sentry->name)+1;
+            if(dsentry->parent_name) {
+                size += sizeof(dsentry->parent_name) + strlen(dsentry->parent_name)+1;
+            }
+        }
+        if(sentry->type == &dsentry->type) {
+            size += sizeof(dsentry->type.num_child_types);
+        }
+        size += sizeof(dsentry->next);
+    }
+    else {
+        size += sizeof(sentry->address);
+        if(flags & MAGIC_SIZE_NAMES) {
+            size += sizeof(sentry->name) + strlen(sentry->name)+1;
+        }
+    }
+
+    return size;
+}
+
+/*===========================================================================*
+ *                           magic_sentries_get_size                         *
+ *===========================================================================*/
+PUBLIC size_t magic_sentries_get_size(int flags)
+{
+    size_t size;
+    int i;
+
+    size = 0;
+    for(i=0;i<_magic_sentries_num;i++) {
+        size += magic_sentry_get_size(&_magic_sentries[i], flags);
+    }
+
+    return size;
+}
+
+/*===========================================================================*
+ *                          magic_dsentries_get_size                         *
+ *===========================================================================*/
+PUBLIC size_t magic_dsentries_get_size(int flags)
+{
+    size_t size;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry* sentry;
+
+    size = 0;
+    MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+        if(!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) {
+            size += magic_sentry_get_size(sentry, flags);
+        }
+    );
+
+    return size;
+}
+
+/*===========================================================================*
+ *                           magic_dsindex_get_size                          *
+ *===========================================================================*/
+PUBLIC size_t magic_dsindex_get_size(struct _magic_dsindex *dsindex, int flags)
+{
+    size_t size;
+
+    size = sizeof(dsindex->type) + sizeof(dsindex->flags);
+
+    if(flags & MAGIC_SIZE_DSINDEX_NAMES) {
+        size += sizeof(dsindex->parent_name) + strlen(dsindex->parent_name)+1;
+        size += sizeof(dsindex->name) + strlen(dsindex->name)+1;
+    }
+
+    return size;
+}
+
+/*===========================================================================*
+ *                          magic_dsindexes_get_size                         *
+ *===========================================================================*/
+PUBLIC size_t magic_dsindexes_get_size(int flags)
+{
+    size_t size;
+    int i;
+
+    size = 0;
+    for(i=0;i<_magic_dsindexes_num;i++) {
+        size += magic_dsindex_get_size(&_magic_dsindexes[i], flags);
+    }
+
+    return size;
+}
+
+/*===========================================================================*
+ *                           magic_sodesc_get_size                           *
+ *===========================================================================*/
+PUBLIC size_t magic_sodesc_get_size(struct _magic_sodesc *sodesc, int flags)
+{
+    return sizeof(struct _magic_sodesc);
+}
+
+/*===========================================================================*
+ *                           magic_sodescs_get_size                          *
+ *===========================================================================*/
+PUBLIC size_t magic_sodescs_get_size(int flags)
+{
+    size_t size;
+    struct _magic_sodesc* sodesc;
+
+    size = 0;
+    MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc,
+        size += magic_sodesc_get_size(sodesc, flags);
+    );
+
+    return size;
+}
+
+/*===========================================================================*
+ *                           magic_dsodesc_get_size                          *
+ *===========================================================================*/
+PUBLIC size_t magic_dsodesc_get_size(struct _magic_dsodesc *dsodesc, int flags)
+{
+    return sizeof(struct _magic_dsodesc);
+}
+
+/*===========================================================================*
+ *                          magic_dsodescs_get_size                          *
+ *===========================================================================*/
+PUBLIC size_t magic_dsodescs_get_size(int flags)
+{
+    size_t size;
+    struct _magic_dsodesc* dsodesc;
+
+    size = 0;
+    MAGIC_DSODESC_ITER(_magic_first_dsodesc, dsodesc,
+        size += magic_dsodesc_get_size(dsodesc, flags);
+    );
+
+    return size;
+}
+
+/*===========================================================================*
+ *                          magic_metadata_get_size                          *
+ *===========================================================================*/
+PUBLIC size_t magic_metadata_get_size(int flags)
+{
+    size_t size = 0;
+
+    size += magic_types_get_size(flags);
+    size += magic_functions_get_size(flags);
+    size += magic_dfunctions_get_size(flags);
+    size += magic_sentries_get_size(flags);
+    size += magic_dsentries_get_size(flags);
+    size += magic_dsindexes_get_size(flags);
+    size += magic_dsodescs_get_size(flags);
+
+    return size;
+}
+
+/*===========================================================================*
+ *                       magic_sentries_data_get_size                        *
+ *===========================================================================*/
+PUBLIC size_t magic_sentries_data_get_size(int flags)
+{
+    size_t size;
+    int i;
+
+    size = 0;
+    for(i=0;i<_magic_sentries_num;i++) {
+        size += _magic_sentries[i].type->size;
+    }
+
+    return size;
+}
+
+/*===========================================================================*
+ *                       magic_dsentries_data_get_size                       *
+ *===========================================================================*/
+PUBLIC size_t magic_dsentries_data_get_size(int flags)
+{
+    size_t size;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry* sentry;
+
+    size = 0;
+    MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+        if(!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) {
+            size += sentry->type->size;
+            if(MAGIC_STATE_FLAG(sentry, MAGIC_STATE_HEAP)) {
+                /* Assume a couple of words for malloc header. */
+                size += 2*sizeof(void*);
+            }
+        }
+    );
+
+    return size;
+}
+
+/*===========================================================================*
+ *                         magic_other_data_get_size                         *
+ *===========================================================================*/
+PUBLIC size_t magic_other_data_get_size(int flags)
+{
+    size_t size = 0;
+
+    MAGIC_DSENTRY_LOCK();
+    magic_range_is_stack(NULL);
+    MAGIC_DSENTRY_UNLOCK();
+    size += MAGIC_RANGE_SIZE(magic_stack_range);
+    size += MAGIC_RANGE_SIZE(magic_text_range);
+
+    return size;
+}
+
+/*===========================================================================*
+ *                            magic_data_get_size                            *
+ *===========================================================================*/
+PUBLIC size_t magic_data_get_size(int flags)
+{
+    size_t size = 0;
+
+    size += magic_sentries_data_get_size(flags);
+    size += magic_dsentries_data_get_size(flags);
+    size += magic_other_data_get_size(flags);
+
+    return size;
+}
+
+/*===========================================================================*
+ *                           magic_print_size_stats                          *
+ *===========================================================================*/
+PUBLIC void magic_print_size_stats(int flags)
+{
+    size_t sentries_data_size, sentries_metadata_size;
+    size_t dsentries_data_size, dsentries_metadata_size;
+    size_t data_size, metadata_size;
+    int dsentries_num;
+    sentries_data_size = magic_sentries_data_get_size(flags);
+    sentries_metadata_size = magic_sentries_get_size(flags);
+    dsentries_data_size = magic_dsentries_data_get_size(flags);
+    dsentries_metadata_size = magic_dsentries_get_size(flags);
+    data_size = magic_data_get_size(flags);
+    metadata_size = magic_metadata_get_size(flags);
+    MAGIC_DSENTRY_NUM(_magic_first_dsentry, &dsentries_num);
+    _magic_printf("--------------------------------------------------------\n");
+    _magic_printf("magic_print_size_stats: Printing size stats:\n");
+    _magic_printf("    - sentries:  # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", _magic_sentries_num, sentries_data_size, sentries_metadata_size, sentries_data_size+sentries_metadata_size, ((double)sentries_metadata_size)/sentries_data_size);
+    _magic_printf("    - dsentries: # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", dsentries_num, dsentries_data_size, dsentries_metadata_size, dsentries_data_size+dsentries_metadata_size, ((double)dsentries_metadata_size)/dsentries_data_size);
+    _magic_printf("    - other:     # %6d, data %8d\n", 2, magic_other_data_get_size(flags));
+    _magic_printf("    - state all: # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", _magic_sentries_num+dsentries_num, sentries_data_size+dsentries_data_size, metadata_size, sentries_data_size+dsentries_data_size+metadata_size, ((double)metadata_size)/(sentries_data_size+dsentries_data_size));
+    _magic_printf("    - all:       # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", _magic_sentries_num+dsentries_num+2, data_size, metadata_size, data_size+metadata_size, ((double)metadata_size)/data_size);
+    _magic_printf("--------------------------------------------------------\n");
+    _magic_printf("magic_print_size_stats: Printing metadata size breakdown:\n");
+    _magic_printf("    - types:     # %6d, metadata %8d\n", _magic_types_num, magic_types_get_size(flags));
+    _magic_printf("    - functions: # %6d, metadata %8d\n", _magic_functions_num, magic_functions_get_size(flags));
+    _magic_printf("    - dfunctions # %6d, metadata %8d\n", 0, magic_dfunctions_get_size(flags));
+    _magic_printf("    - sentries:  # %6d, metadata %8d\n", _magic_sentries_num, sentries_metadata_size);
+    _magic_printf("    - dsentries: # %6d, metadata %8d\n", dsentries_num, dsentries_metadata_size);
+    _magic_printf("    - dsindexes: # %6d, metadata %8d\n", _magic_dsindexes_num, magic_dsindexes_get_size(flags));
+    _magic_printf("    - dsodescs:  # %6d, metadata %8d\n", 0, magic_dsodescs_get_size(flags));
+    _magic_printf("--------------------------------------------------------\n");
+}
+
diff --git a/minix/llvm/static/magic/magic_analysis.c b/minix/llvm/static/magic/magic_analysis.c
new file mode 100644 (file)
index 0000000..bfb9e44
--- /dev/null
@@ -0,0 +1,1065 @@
+
+#include <magic_analysis.h>
+
+PUBLIC char magic_ne_str[] =  "NULL_TYPE";
+PUBLIC char magic_enf_str[] = "UNKNOWN_TYPE";
+PUBLIC char magic_bo_str[] =  "BAD_TYPE";
+PUBLIC char magic_be_str[] =  "BAD_ENTRY_TYPE";
+PUBLIC char magic_bv_str[] =  "BAD_VALUE_TYPE";
+PUBLIC char magic_vf_str[] =  "VALUE_FOUND_TYPE";
+PUBLIC const struct _magic_type magic_NULL_ENTRY_TYPE =      MAGIC_TYPE_SPECIAL_INIT(magic_ne_str);
+PUBLIC const struct _magic_type magic_ENTRY_NOT_FOUND_TYPE = MAGIC_TYPE_SPECIAL_INIT(magic_enf_str);
+PUBLIC const struct _magic_type magic_BAD_OFFSET_TYPE =      MAGIC_TYPE_SPECIAL_INIT(magic_bo_str);
+PUBLIC const struct _magic_type magic_BAD_ENTRY_TYPE =       MAGIC_TYPE_SPECIAL_INIT(magic_be_str);
+PUBLIC const struct _magic_type magic_BAD_VALUE_TYPE =       MAGIC_TYPE_SPECIAL_INIT(magic_bv_str);
+PUBLIC const struct _magic_type magic_VALUE_FOUND =          MAGIC_TYPE_SPECIAL_INIT(magic_vf_str);
+
+PRIVATE magic_cb_sentries_analyze_pre_t magic_sentries_analyze_pre_cb = NULL;
+
+/*===========================================================================*
+ *                      magic_setcb_sentries_analyze_pre                     *
+ *===========================================================================*/
+PUBLIC void magic_setcb_sentries_analyze_pre(magic_cb_sentries_analyze_pre_t cb)
+{
+    magic_sentries_analyze_pre_cb = cb;
+}
+
+/*===========================================================================*
+ *                        magic_sentry_print_ptr_types                       *
+ *===========================================================================*/
+PUBLIC int magic_sentry_print_ptr_types(struct _magic_sentry* entry)
+{
+    int ret, ptrs_found = 0;
+    void* args_array[2];
+    args_array[0] = entry;
+    args_array[1] = &ptrs_found;
+    ret = magic_type_walk_root_all(entry->type, magic_type_examine_ptr_cb, args_array);
+    assert(ret >= 0);
+    return ptrs_found;
+}
+
+/*===========================================================================*
+ *                         magic_sentry_extract_ptrs                         *
+ *===========================================================================*/
+PUBLIC int magic_sentry_extract_ptrs(struct _magic_sentry* entry, void ****ptr_map, const struct _magic_type ***ptr_type_map, int *ptr_num)
+{
+    int from_wrapper = MAGIC_MEM_WRAPPER_IS_ACTIVE();
+    int ret = magic_type_count_ptrs(entry->type, ptr_num);
+    assert(ret == 0);
+    if(*ptr_num == 0) {
+        *ptr_map = NULL;
+        *ptr_type_map = NULL;
+    }
+    else {
+        void* args_array[4];
+        int ptr_num2 = 0;
+        if(!from_wrapper) {
+            MAGIC_MEM_WRAPPER_BEGIN();
+        }
+        *ptr_map = (void ***) malloc((*ptr_num)*sizeof(void **));
+        *ptr_type_map = (const struct _magic_type **) malloc((*ptr_num)*sizeof(const struct _magic_type *));
+        if(!from_wrapper) {
+            MAGIC_MEM_WRAPPER_END();
+        }
+        args_array[0] = entry;
+        args_array[1] = *ptr_map;
+        args_array[2] = *ptr_type_map;
+        args_array[3] = &ptr_num2;
+        ret = magic_type_walk_root_all(entry->type, magic_type_extract_ptr_cb, args_array);
+        assert(ret >= 0);
+        assert(*ptr_num == ptr_num2);
+    }
+    return 0;
+}
+
+/*===========================================================================*
+ *                           magic_sentry_analyze                            *
+ *===========================================================================*/
+PUBLIC int magic_sentry_analyze(struct _magic_sentry* sentry, int flags,
+    const magic_sentry_analyze_cb_t cb, void* cb_args,
+    _magic_sel_stats_t *sentry_stats)
+{
+    int ret;
+    int selement_num = 0, sel_analyzed_num = 0;
+    void* args_array[7];
+    args_array[0] = (void*) &flags;
+    args_array[1] = (void*) &cb;
+    args_array[2] = (void*) cb_args;
+    args_array[3] = (void*) sentry;
+    args_array[4] = (void*) sentry_stats;
+    args_array[5] = (void*) &selement_num;
+    args_array[6] = (void*) &sel_analyzed_num;
+    ret = magic_type_walk_root_all(sentry->type, magic_type_analyzer_cb,
+        args_array);
+    if(ret < 0) {
+        return ret;
+    }
+
+    return flags;
+}
+
+/*===========================================================================*
+ *                          magic_sentries_analyze                           *
+ *===========================================================================*/
+PUBLIC int magic_sentries_analyze(int flags, const magic_sentry_analyze_cb_t cb,
+    void *cb_args, _magic_sel_stats_t *sentries_stats)
+{
+    int i, ret;
+    struct _magic_sentry *sentry;
+
+    if (flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)
+        magic_reentrant_disable();
+
+    /* See if any pre-analyze callback has been registered. */
+    if (magic_sentries_analyze_pre_cb) {
+        ret = magic_sentries_analyze_pre_cb();
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    /* Analyze all the sentries. */
+    for (i = 0 ; i < _magic_sentries_num ; i++) {
+        sentry = &_magic_sentries[i];
+        ret = magic_sentry_analyze(sentry, flags, cb, cb_args, sentries_stats);
+        if (ret < 0) {
+            return ret;
+        }
+        else {
+            flags |= ret;
+        }
+    }
+
+    /* Analyze all the dsentries if asked to. */
+    if (flags & MAGIC_SEL_ANALYZE_DYNAMIC) {
+        return magic_dsentries_analyze(flags, cb, cb_args, sentries_stats);
+    }
+
+    if (flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)
+        magic_reentrant_enable();
+
+    return flags;
+}
+
+/*===========================================================================*
+ *                       magic_sentry_print_selements                        *
+ *===========================================================================*/
+PUBLIC int magic_sentry_print_selements(struct _magic_sentry* sentry)
+{
+    int flags = (MAGIC_SEL_ANALYZE_POINTERS|MAGIC_SEL_ANALYZE_NONPOINTERS|MAGIC_SEL_ANALYZE_DATA|MAGIC_SEL_ANALYZE_INVARIANTS|MAGIC_SEL_ANALYZE_VIOLATIONS);
+    return magic_sentry_analyze(sentry, flags, magic_sentry_print_el_cb, NULL, NULL);
+}
+
+/*===========================================================================*
+ *                     magic_sentry_print_ptr_selements                      *
+ *===========================================================================*/
+PUBLIC int magic_sentry_print_ptr_selements(struct _magic_sentry* sentry,
+    int skip_null_ptrs, int max_target_recusions)
+{
+    int flags = (MAGIC_SEL_ANALYZE_POINTERS|MAGIC_SEL_ANALYZE_DATA|MAGIC_SEL_ANALYZE_INVARIANTS|MAGIC_SEL_ANALYZE_VIOLATIONS);
+    void* args_array[2];
+    args_array[0] = &skip_null_ptrs;
+    args_array[1] = &max_target_recusions;
+    return magic_sentry_analyze(sentry, flags, magic_sentry_print_ptr_el_cb, args_array, NULL);
+}
+
+/*===========================================================================*
+ *                         magic_dsentries_analyze                           *
+ *===========================================================================*/
+PUBLIC int magic_dsentries_analyze(int flags, const magic_sentry_analyze_cb_t cb,
+    void *cb_args, _magic_sel_stats_t *dsentries_stats)
+{
+    int ret = 0;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry* sentry;
+
+    /* If dead dsentries are enabled, garbage collect them to ensure consistency. */
+    if (magic_allow_dead_dsentries)
+        magic_free_dead_dsentries();
+
+    /* Analyze all the dsentries. */
+    /*
+     * We need to hold the DSENTRY, DFUNCTION and DSODESC locks for the
+     * magic_range_lookup_by_addr() function.
+     */
+    MAGIC_MULTIPLE_LOCK(1, 1, 1, 0);
+    MAGIC_DSENTRY_ALIVE_BLOCK_ITER(_magic_first_dsentry, prev_dsentry, dsentry,
+        sentry,
+
+        /*
+         * Check if we should analyze out-of-band dsentries.
+         */
+        if (!(flags & MAGIC_SEL_ANALYZE_OUT_OF_BAND) &&
+            MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) {
+            continue;
+        }
+
+        /*
+         * Check if we should analyze shlib state dsentries.
+         */
+        if (!(flags & MAGIC_SEL_ANALYZE_LIB_SRC) &&
+            MAGIC_STATE_FLAG(sentry, MAGIC_STATE_LIB)) {
+            continue;
+        }
+
+        ret = magic_sentry_analyze(sentry, flags, cb, cb_args, dsentries_stats);
+        if (ret < 0) {
+            break;
+        }
+        else {
+            flags |= ret;
+        }
+    );
+    MAGIC_MULTIPLE_UNLOCK(1, 1, 1, 0);
+
+    return ret < 0 ? ret : flags;
+}
+
+/*===========================================================================*
+ *                         magic_sentry_print_el_cb                          *
+ *===========================================================================*/
+PUBLIC int magic_sentry_print_el_cb(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args)
+{
+    if(sel_analyzed->num == 1) {
+        MAGIC_SENTRY_PRINT(selement->sentry, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+    }
+
+    MAGIC_SELEMENT_PRINT(selement, MAGIC_EXPAND_TYPE_STR);
+    _magic_printf("\n");
+    MAGIC_SEL_ANALYZED_PRINT(sel_analyzed, MAGIC_EXPAND_TYPE_STR);
+    _magic_printf("\n");
+    MAGIC_SEL_STATS_PRINT(sel_stats);
+    _magic_printf("\n\n");
+
+    return MAGIC_SENTRY_ANALYZE_CONTINUE;
+}
+
+/*===========================================================================*
+ *                      magic_sentry_print_ptr_el_cb                         *
+ *===========================================================================*/
+PUBLIC int magic_sentry_print_ptr_el_cb(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args)
+{
+    int r;
+    void** args_array = (void**) cb_args;
+    int skip_null_ptrs = args_array ? *((int*)args_array[0]) : 0;
+    int max_target_recursions = args_array ? *((int*)args_array[1]) : 0;
+
+    if(sel_analyzed->type_id != MAGIC_TYPE_POINTER) {
+        return MAGIC_SENTRY_ANALYZE_CONTINUE;
+    }
+    if(skip_null_ptrs && sel_analyzed->u.ptr.value == 0) {
+        return MAGIC_SENTRY_ANALYZE_CONTINUE;
+    }
+    magic_sentry_print_el_cb(selement, sel_analyzed, sel_stats, cb_args);
+    if(max_target_recursions>0 && !(sel_analyzed->flags & MAGIC_SEL_FOUND_VIOLATIONS)) {
+        struct _magic_sentry *sentry = &sel_analyzed->u.ptr.trg.dsentry.sentry;
+        if(MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(sel_analyzed) && MAGIC_SENTRY_ID(sentry)!=MAGIC_SENTRY_ID(selement->sentry)) {
+            r = magic_sentry_print_ptr_selements(sentry, skip_null_ptrs,
+                max_target_recursions-1);
+            if(r < 0) {
+                _magic_printf("magic_sentry_print_ptr_el_cb: recursive step reported error %d\n", r);
+                return r;
+            }
+        }
+    }
+
+    return MAGIC_SENTRY_ANALYZE_CONTINUE;
+}
+
+/*===========================================================================*
+ *                   magic_sentry_print_el_with_trg_reg_cb                   *
+ *===========================================================================*/
+PUBLIC int magic_sentry_print_el_with_trg_reg_cb(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args)
+{
+    if(MAGIC_SEL_ANALYZED_TRG_FLAGS(sel_analyzed)) {
+        return magic_sentry_print_el_cb(selement, sel_analyzed, sel_stats,
+            cb_args);
+    }
+
+    return MAGIC_SENTRY_ANALYZE_CONTINUE;
+}
+
+/*===========================================================================*
+ *                     magic_sentry_print_el_with_trg_cb                     *
+ *===========================================================================*/
+PUBLIC int magic_sentry_print_el_with_trg_cb(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args)
+{
+    if(MAGIC_SEL_ANALYZED_TRG_FLAGS(sel_analyzed)
+        && MAGIC_SELEMENT_HAS_TRG(selement)) {
+        return magic_sentry_print_el_cb(selement, sel_analyzed, sel_stats,
+            cb_args);
+    }
+
+    return MAGIC_SENTRY_ANALYZE_CONTINUE;
+}
+
+/*===========================================================================*
+ *                          magic_type_count_ptrs                            *
+ *===========================================================================*/
+PUBLIC int magic_type_count_ptrs(const struct _magic_type* type, int* ptr_num)
+{
+    int ret;
+    void* args_array[4] = { NULL, NULL, NULL };
+    args_array[3] = ptr_num;
+    *ptr_num = 0;
+    ret = magic_type_walk_root_all(type, magic_type_extract_ptr_cb, args_array);
+    assert(ret >= 0);
+    return 0;
+}
+
+/*===========================================================================*
+ *                         magic_type_examine_ptr_cb                         *
+ *===========================================================================*/
+PUBLIC int magic_type_examine_ptr_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num,
+    const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
+{
+    int ret;
+    void** args_array = (void**) cb_args;
+    if(type->type_id == MAGIC_TYPE_POINTER) {
+        const struct _magic_sentry *root_entry = (const struct _magic_sentry *) args_array[0];
+        int *ptrs_found = (int*) args_array[1];
+        char* root_address = root_entry->address;
+        void* ptr_address = root_address ? root_address+offset : NULL;
+        void* target_address = ptr_address ? *((void**)ptr_address) : NULL;
+        (*ptrs_found)++;
+        _magic_printf("Pointer found for root entry (name=%s, address=0x%08x) at offset %d, static target type is: ", root_entry->name, (unsigned) root_address, offset);
+        magic_type_str_print(type->contained_types[0]);
+        _magic_printf(" - dynamic target types are: ");
+        if(!target_address) {
+            _magic_printf("NULL");
+        }
+        else {
+            ret = magic_type_str_print_from_target(target_address);
+            if(ret < 0) {
+                _magic_printf("ENTRY NOT FOUND");
+            }
+        }
+        _magic_printf("\n");
+    }
+    return MAGIC_TYPE_WALK_CONTINUE;
+}
+
+/*===========================================================================*
+ *                         magic_type_extract_ptr_cb                         *
+ *===========================================================================*/
+PUBLIC int magic_type_extract_ptr_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num,
+    const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
+{
+    void** args_array = (void**) cb_args;
+    static void* null_ptr=NULL;
+    if(type->type_id == MAGIC_TYPE_POINTER) {
+        const struct _magic_sentry *root_entry = (const struct _magic_sentry *) args_array[0];
+        void ***ptr_map = (void ***) args_array[1];
+        const struct _magic_type **ptr_type_map = (const struct _magic_type **) args_array[2];
+        int *ptr_num = (int*) args_array[3];
+        char* root_ptr;
+        void** ptr_ptr;
+        assert(ptr_num);
+        if(root_entry && ptr_map && ptr_type_map) {
+            root_ptr = root_entry->address;
+            ptr_ptr= root_ptr ? (void**)(root_ptr+offset) : &null_ptr;
+            ptr_map[*ptr_num] = ptr_ptr;
+            ptr_type_map[*ptr_num] = type;
+        }
+        (*ptr_num)++;
+    }
+    return MAGIC_TYPE_WALK_CONTINUE;
+}
+
+/*===========================================================================*
+ *                           magic_type_analyzer_cb                          *
+ *===========================================================================*/
+PUBLIC int magic_type_analyzer_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num, const struct _magic_type* type,
+    const unsigned offset, int depth, void* cb_args)
+{
+    int ret;
+    void **args_array = (void **) cb_args;
+    int *flags = (int *)args_array[0];
+    magic_sentry_analyze_cb_t sentry_analyze_cb =
+        *((magic_sentry_analyze_cb_t *) args_array[1]);
+    void *sentry_analyze_cb_args = (void *) args_array[2];
+    struct _magic_sentry* sentry = (struct _magic_sentry *) args_array[3];
+    _magic_sel_stats_t *sentry_stats = (_magic_sel_stats_t *) args_array[4];
+    int *selement_num = (int *) args_array[5];
+    int *sel_analyzed_num = (int *) args_array[6];
+    static int likely_pointer_orig_type_id;
+    static int likely_pointer_orig_contained_type_id;
+    _magic_selement_t selement;
+    _magic_sel_analyzed_t sel_analyzed;
+    _magic_sel_stats_t sel_stats;
+
+    if (type->type_id == MAGIC_TYPE_UNION &&
+        ((*flags) & MAGIC_SEL_SKIP_UNIONS)) {
+        /* Skip unions when requested. */
+        return MAGIC_TYPE_WALK_SKIP_PATH;
+    }
+
+    if ((type->type_id == MAGIC_TYPE_INTEGER ||
+            type->type_id == MAGIC_TYPE_ENUM) &&
+            ((*flags) & MAGIC_SEL_SKIP_INTEGERS)) {
+        /* Skip integers when requested. */
+        return MAGIC_TYPE_WALK_SKIP_PATH;
+    }
+
+    if (((*flags) & MAGIC_SEL_ANALYZE_LIKELYPOINTERS) &&
+        (MAGIC_TYPE_IS_RAW_ARRAY(type) ||
+        (MAGIC_TYPE_IS_INT_ARRAY(type) &&
+            type->contained_types[0]->size != sizeof(void *) &&
+            type->size >= sizeof(void *)) ||
+        (type->type_id == MAGIC_TYPE_INTEGER && type->size > sizeof(void *)))) {
+        /* This can be either UNION, INTEGER or ARRAY (of VOID or INTEGER). */
+        likely_pointer_orig_type_id = type->type_id;
+        if (type->type_id == MAGIC_TYPE_ARRAY)
+            likely_pointer_orig_contained_type_id =
+                type->contained_types[0]->type_id;
+        /* Try to find likely pointers in raw arrays. */
+        ret = magic_type_walk_as_ptrint_array(parent_type, parent_offset,
+            child_num, type, (char *)sentry->address + offset, offset,
+            0, ULONG_MAX, magic_type_analyzer_cb, cb_args);
+        likely_pointer_orig_type_id = likely_pointer_orig_contained_type_id = 0;
+        if (ret != MAGIC_EBADWALK) {
+            return ret == 0 ? MAGIC_TYPE_WALK_SKIP_PATH : ret;
+        }
+    }
+
+    selement.sentry = sentry;
+    selement.parent_type = parent_type;
+    selement.parent_address = (char *)sentry->address + parent_offset;
+    selement.child_num = child_num;
+    selement.type = type;
+    selement.address = (char *)sentry->address + offset;
+    selement.depth = depth;
+    selement.num = ++(*selement_num);
+    selement.cb_args = cb_args;
+
+    ret = magic_selement_analyze(&selement, *flags, &sel_analyzed, &sel_stats);
+    if (ret &&
+        (((ret & MAGIC_SEL_FOUND_DATA) &&
+          ((*flags) & MAGIC_SEL_ANALYZE_DATA)) ||
+         ((ret & MAGIC_SEL_FOUND_INVARIANTS) &&
+          ((*flags) & MAGIC_SEL_ANALYZE_INVARIANTS)) ||
+         ((ret & MAGIC_SEL_FOUND_VIOLATIONS) &&
+          ((*flags) & MAGIC_SEL_ANALYZE_VIOLATIONS)) ||
+         ((ret & MAGIC_SEL_FOUND_WALKABLE) &&
+          ((*flags) & MAGIC_SEL_ANALYZE_WALKABLE))
+        )) {
+        *flags |= ret;
+        sel_analyzed.num = ++(*sel_analyzed_num);
+        if (likely_pointer_orig_type_id) {
+            sel_analyzed.type_id = likely_pointer_orig_type_id;
+            sel_analyzed.contained_type_id =
+                likely_pointer_orig_contained_type_id;
+        }
+        ret = sentry_analyze_cb(&selement, &sel_analyzed, &sel_stats,
+            sentry_analyze_cb_args);
+        if (sel_analyzed.flags & MAGIC_SEL_FOUND_INVARIANTS) {
+            _magic_sel_stats_t* sel_stats_ptr = &sel_stats;
+            if (sentry_stats) {
+                MAGIC_SEL_STATS_INCR(sentry_stats, sel_stats_ptr);
+            }
+        }
+        if (ret != MAGIC_SENTRY_ANALYZE_CONTINUE) {
+            switch (ret) {
+                case MAGIC_SENTRY_ANALYZE_SKIP_PATH:
+                    ret = MAGIC_TYPE_WALK_SKIP_PATH;
+                break;
+                case MAGIC_SENTRY_ANALYZE_STOP:
+                    ret = MAGIC_TYPE_WALK_STOP;
+                break;
+                default:
+                    assert(ret < 0 && "Invalid error code!");
+                break;
+            }
+            return ret;
+        }
+    }
+
+    return MAGIC_TYPE_WALK_CONTINUE;
+}
+
+/*===========================================================================*
+ *                          magic_selement_analyze                           *
+ *===========================================================================*/
+PUBLIC int magic_selement_analyze(_magic_selement_t *selement, int flags,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
+{
+    const struct _magic_type *type = selement->type;
+    short is_ptr_el = type->type_id == MAGIC_TYPE_POINTER;
+    short is_nonptr_el = type->num_child_types == 0 || (type->type_id == MAGIC_TYPE_INTEGER && type->num_child_types > 0);
+    short analyze_ptr_el, analyze_nonptr_el;
+
+    if (!is_ptr_el && !is_nonptr_el) {
+        if (MAGIC_TYPE_IS_WALKABLE(type)) {
+            sel_analyzed->type_id = MAGIC_TYPE_OPAQUE;
+            return MAGIC_SEL_FOUND_WALKABLE;
+        }
+        /* Not an element to analyze. */
+        return 0;
+    }
+    assert(is_ptr_el ^ is_nonptr_el);
+
+    analyze_ptr_el = is_ptr_el && (flags & MAGIC_SEL_ANALYZE_POINTERS);
+    analyze_nonptr_el = 0;
+    if (is_nonptr_el && ((flags & MAGIC_SEL_ANALYZE_DATA) || MAGIC_TYPE_HAS_VALUE_SET(type))) {
+        if (flags & MAGIC_SEL_ANALYZE_NONPOINTERS) {
+            analyze_nonptr_el = 1;
+        }
+        else if (flags & MAGIC_SEL_ANALYZE_LIKELYPOINTERS) {
+            short is_intvalue_el = type->type_id == MAGIC_TYPE_ENUM
+                || type->type_id == MAGIC_TYPE_INTEGER;
+            if (is_intvalue_el && type->size == sizeof(void *)) {
+                long value = magic_selement_to_int(selement);
+                analyze_nonptr_el = MAGIC_INT_IS_LIKELY_PTR(value);
+            }
+        }
+    }
+
+    if (analyze_nonptr_el && (flags & MAGIC_SEL_ANALYZE_NONPTRS_AS_PTRS) &&
+        type->size == sizeof(void *)) {
+        struct _magic_type tmp_type;
+        int ret;
+        tmp_type = *(selement->type);
+        tmp_type.type_id = MAGIC_TYPE_POINTER;
+        selement->type = &tmp_type;
+
+        /* Analyze non-pointer element as a pointer. */
+        ret = magic_selement_analyze_ptr(selement, flags, sel_analyzed, sel_stats);
+
+        selement->type = type;
+        /* Keep original type in sel_analyzed. */
+        sel_analyzed->type_id = type->type_id;
+
+        return ret;
+    }
+
+    assert(!analyze_ptr_el || !analyze_nonptr_el);
+
+    if (analyze_ptr_el) {
+        /* Analyze pointer element. */
+        return magic_selement_analyze_ptr(selement, flags, sel_analyzed,
+            sel_stats);
+    }
+    if (analyze_nonptr_el) {
+        /* Analyze nonpointer element. */
+        return magic_selement_analyze_nonptr(selement, flags, sel_analyzed,
+            sel_stats);
+    }
+
+    /* Nothing to analyze. */
+    return 0;
+}
+
+/*===========================================================================*
+ *                   magic_selement_analyze_ptr_value_invs                   *
+ *===========================================================================*/
+PUBLIC int magic_selement_analyze_ptr_value_invs(_magic_selement_t *selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
+{
+    const struct _magic_type* ptr_type = selement->type;
+    int i, ret = 0;
+    const struct _magic_type *first_trg_type;
+    void* value = sel_analyzed->u.ptr.value;
+
+    first_trg_type = MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(sel_analyzed);
+    assert(sel_analyzed->u.ptr.num_trg_types > 0 && first_trg_type);
+    if(first_trg_type == MAGIC_TYPE_NULL_ENTRY) {
+        ret |= MAGIC_SEL_FOUND_INVARIANTS;
+        sel_stats->null_type_found++;
+    }
+    else if(MAGIC_TYPE_FLAG(ptr_type, MAGIC_TYPE_INT_CAST)) {
+        if(MAGIC_TYPE_HAS_VALUE_SET(ptr_type)) {
+            i=0;
+            while(MAGIC_TYPE_HAS_VALUE(ptr_type, i)) {
+                int trg_value = MAGIC_TYPE_VALUE(ptr_type, i);
+                if(trg_value == (int) value) {
+                    ret |= MAGIC_SEL_FOUND_INVARIANTS;
+                    MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_VALUE_FOUND);
+                    sel_stats->value_found++;
+                    break;
+                }
+                i++;
+            }
+            if(!(ret & MAGIC_SEL_FOUND_INVARIANTS) && MAGIC_TYPE_FLAG(ptr_type, MAGIC_TYPE_STRICT_VALUE_SET)) {
+                ret |= MAGIC_SEL_FOUND_INVARIANTS;
+                MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_BAD_VALUE);
+                sel_stats->badvalue_found++;
+            }
+        }
+        else if(MAGIC_PTR_IS_LIKELY_INT(value)) {
+            ret |= MAGIC_SEL_FOUND_INVARIANTS;
+            MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_VALUE_FOUND);
+            sel_stats->value_found++;
+        }
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                    magic_selement_analyze_ptr_trg_invs                    *
+ *===========================================================================*/
+PUBLIC int magic_selement_analyze_ptr_trg_invs(_magic_selement_t *selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
+{
+    int ret = 0;
+    const struct _magic_type *first_trg_type;
+
+    first_trg_type = MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(sel_analyzed);
+    assert(sel_analyzed->u.ptr.num_trg_types > 0 && first_trg_type);
+    sel_stats->trg_flags |= sel_analyzed->u.ptr.trg_flags;
+    if(first_trg_type == MAGIC_TYPE_ENTRY_NOT_FOUND) {
+        ret |= MAGIC_SEL_FOUND_INVARIANTS;
+        sel_stats->unknown_found++;
+    }
+    else if(first_trg_type == MAGIC_TYPE_BAD_ENTRY) {
+        ret |= MAGIC_SEL_FOUND_INVARIANTS;
+        sel_stats->badentry_found++;
+    }
+    else if(first_trg_type == MAGIC_TYPE_BAD_OFFSET) {
+        ret |= MAGIC_SEL_FOUND_INVARIANTS;
+        sel_stats->badoffset_found++;
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                      magic_selement_analyze_ptr_target                    *
+ *===========================================================================*/
+PUBLIC _magic_trg_stats_t magic_selement_analyze_ptr_target(const struct _magic_type *ptr_type,
+    const struct _magic_type *trg_type, int trg_flags)
+{
+    const struct _magic_type* type = ptr_type->contained_types[0];
+
+    /* Analyze void target types first. */
+    if(MAGIC_TYPE_IS_VOID(trg_type)) {
+        int ptr_can_point_to_text = magic_type_ptr_is_text(ptr_type);
+        int ptr_can_point_to_data = magic_type_ptr_is_data(ptr_type);
+        int is_trg_data = (MAGIC_STATE_FLAGS_REGION(trg_flags) & ~MAGIC_STATE_TEXT) != 0;
+        int is_trg_text = trg_flags & MAGIC_STATE_TEXT;
+        assert(ptr_can_point_to_text || ptr_can_point_to_data);
+        assert(is_trg_text || is_trg_data);
+        if((!ptr_can_point_to_text && is_trg_text)
+            || (!ptr_can_point_to_data && is_trg_data)) {
+            return _badentry_found;
+        }
+        else {
+            return _void_type_found;
+        }
+    }
+
+    /* Analyze void types next. */
+    if(MAGIC_TYPE_IS_VOID(type)) {
+        /* Pretend the pointer has been found, void* can point to any valid target. */
+        return _ptr_type_found;
+    }
+
+    /* See if the target type is compatible with the static type. */
+    if(magic_type_compatible(trg_type, type, 0)) {
+        return _ptr_type_found;
+    }
+
+    /* See if the target type is compatible with some static cast type. */
+    if(MAGIC_TYPE_HAS_COMP_TYPES(ptr_type) && magic_type_comp_compatible(ptr_type, trg_type)) {
+        return _comp_trg_types_found;
+    }
+
+    /* No chance. The pointer is pointing to some other invalid type. */
+    return _other_types_found;
+}
+
+/*===========================================================================*
+ *                    magic_selement_analyze_ptr_type_invs                   *
+ *===========================================================================*/
+PUBLIC int magic_selement_analyze_ptr_type_invs(_magic_selement_t *selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
+{
+    const struct _magic_type* ptr_type = selement->type;
+    int i, ret = 0;
+    int trg_flags;
+    const struct _magic_type *trg_type;
+    _magic_trg_stats_t trg_stats;
+
+    assert(sel_analyzed->u.ptr.num_trg_types > 0);
+    if(MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(sel_analyzed)) {
+        /* No invariants if we only have a special target type. */
+        return ret;
+    }
+    trg_flags= sel_analyzed->u.ptr.trg_flags;
+    sel_stats->trg_flags |= trg_flags;
+    ret |= MAGIC_SEL_FOUND_INVARIANTS;
+
+    /* Analyze targets. */
+    sel_analyzed->u.ptr.first_legal_trg_type = -1;
+    sel_analyzed->u.ptr.num_legal_trg_types = 0;
+    for(i=0;i<sel_analyzed->u.ptr.num_trg_types;i++) {
+        trg_type = sel_analyzed->u.ptr.trg_selements[i].type;
+        trg_stats = magic_selement_analyze_ptr_target(ptr_type, trg_type, trg_flags);
+        sel_analyzed->u.ptr.trg_stats[i] = trg_stats;
+        if(!MAGIC_SEL_ANALYZED_TRG_STATS_HAS_VIOLATIONS(trg_stats)) {
+            sel_analyzed->u.ptr.num_legal_trg_types++;
+            if(sel_analyzed->u.ptr.first_legal_trg_type == -1) {
+                sel_analyzed->u.ptr.first_legal_trg_type = i;
+            }
+        }
+    }
+
+    /* Set global stats. */
+    for(i=0;i<sel_analyzed->u.ptr.num_trg_types;i++) {
+        trg_stats = sel_analyzed->u.ptr.trg_stats[i];
+        if(trg_stats == _badentry_found) {
+            sel_stats->badentry_found++;
+            return ret;
+        }
+        else if(trg_stats == _void_type_found) {
+            sel_stats->void_type_found++;
+            return ret;
+        }
+    }
+    for(i=0;i<sel_analyzed->u.ptr.num_trg_types;i++) {
+        trg_stats = sel_analyzed->u.ptr.trg_stats[i];
+        if(trg_stats == _ptr_type_found) {
+            sel_stats->ptr_type_found++;
+            return ret;
+        }
+    }
+    for(i=0;i<sel_analyzed->u.ptr.num_trg_types;i++) {
+        trg_stats = sel_analyzed->u.ptr.trg_stats[i];
+        if(trg_stats == _comp_trg_types_found) {
+            sel_stats->comp_trg_types_found++;
+            return ret;
+        }
+    }
+    sel_stats->other_types_found++;
+    return ret;
+}
+
+/*===========================================================================*
+ *                          magic_selement_recurse_ptr                       *
+ *===========================================================================*/
+PUBLIC int magic_selement_recurse_ptr(_magic_selement_t *selement,
+    _magic_selement_t *new_selement, int max_steps)
+{
+    _magic_sel_stats_t sel_stats;
+    _magic_sel_analyzed_t sel_analyzed;
+    int steps = 0;
+
+    if(selement->type->type_id != MAGIC_TYPE_POINTER) {
+        return MAGIC_EINVAL;
+    }
+
+    *new_selement = *selement;
+    while(1) {
+        magic_selement_analyze_ptr(new_selement, MAGIC_SEL_ANALYZE_ALL,
+            &sel_analyzed, &sel_stats);
+        if(MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(&sel_analyzed)) {
+            return steps;
+        }
+        *new_selement = sel_analyzed.u.ptr.trg_selements[0];
+        steps++;
+        if(new_selement->type->type_id != MAGIC_TYPE_POINTER || (max_steps > 0 && steps >= max_steps)) {
+            break;
+        }
+    }
+
+    return steps;
+}
+
+/*===========================================================================*
+ *                         magic_sentry_analyze_ptr_trg_cb                   *
+ *===========================================================================*/
+PRIVATE int magic_sentry_analyze_ptr_trg_cb(const struct _magic_type *trg_parent_type,
+    const unsigned parent_offset, int child_num,
+    const struct _magic_type *trg_type, const unsigned offset, int depth, void *cb_args)
+{
+    void **args_array = (void **) cb_args;
+    _magic_sel_analyzed_t *sel_analyzed = (_magic_sel_analyzed_t *) args_array[3];
+    _magic_selement_t *sel;
+    char *trg_address;
+    int analysis_flags = (*(int *)(args_array[4]));
+
+    if (trg_type->type_id == MAGIC_TYPE_ARRAY) {
+        /* Skip arrays. */
+        return MAGIC_TYPE_WALK_CONTINUE;
+    }
+
+    if (!sel_analyzed->u.ptr.trg_flags) {
+        /* Set trg flags and offset only the first time. */
+        struct _magic_dsentry **trg_dsentry = (struct _magic_dsentry **) args_array[0];
+        struct _magic_dfunction **trg_dfunction = (struct _magic_dfunction **) args_array[1];
+        int flags;
+        if (*trg_dsentry) {
+            assert(!(*trg_dfunction));
+            flags = MAGIC_DSENTRY_TO_SENTRY(*trg_dsentry)->flags;
+            if (flags & MAGIC_STATE_DYNAMIC) {
+                assert(!(flags & MAGIC_STATE_DATA) || (flags & MAGIC_STATE_LIB));
+                assert(MAGIC_STATE_REGION(MAGIC_DSENTRY_TO_SENTRY(*trg_dsentry)));
+            }
+            else {
+                assert((flags & MAGIC_STATE_DATA) && !(flags & MAGIC_STATE_LIB));
+            }
+        }
+        else {
+            assert(*trg_dfunction);
+            flags = MAGIC_DFUNCTION_TO_FUNCTION(*trg_dfunction)->flags;
+            assert(flags & MAGIC_STATE_TEXT);
+        }
+        sel_analyzed->u.ptr.trg_flags = flags;
+        if (analysis_flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)
+            sel_analyzed->u.ptr.trg_flags |= MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS;
+        sel_analyzed->u.ptr.trg_offset = offset;
+    }
+
+    /* Add target types. */
+    trg_address = MAGIC_SEL_ANALYZED_PTR_TRG_ADDRESS(sel_analyzed);
+    assert(trg_address);
+    sel = &sel_analyzed->u.ptr.trg_selements[sel_analyzed->u.ptr.num_trg_types];
+    if (!(analysis_flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)) {
+        sel->sentry = MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(sel_analyzed) ? MAGIC_DSENTRY_TO_SENTRY(&sel_analyzed->u.ptr.trg.dsentry) : NULL;
+    } else {
+        sel->sentry = MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(sel_analyzed) ? MAGIC_DSENTRY_TO_SENTRY(sel_analyzed->u.ptr.trg_p.dsentry) : NULL;
+    }
+    sel->parent_type = trg_parent_type;
+    sel->parent_address = trg_address + parent_offset;
+    sel->child_num = child_num;
+    sel->type = trg_type;
+    sel->address = trg_address + offset;
+    sel_analyzed->u.ptr.num_trg_types++;
+
+    return MAGIC_TYPE_WALK_CONTINUE;
+}
+
+/*===========================================================================*
+ *                        magic_selement_analyze_ptr                         *
+ *===========================================================================*/
+PUBLIC int magic_selement_analyze_ptr(_magic_selement_t *selement, int flags,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
+{
+    const struct _magic_type *ptr_type = selement->type;
+    short is_ptr_el = ptr_type->type_id == MAGIC_TYPE_POINTER;
+    int r, ret = 0;
+
+    sel_analyzed->type_id = 0;
+    if (!is_ptr_el) {
+        /* Nothing to do. */
+        return 0;
+    }
+    memset(&sel_analyzed->u.ptr, 0, sizeof(sel_analyzed->u.ptr));
+    memset(sel_stats, 0, sizeof(_magic_sel_stats_t));
+
+    if (flags & (MAGIC_SEL_ANALYZE_DATA | MAGIC_SEL_ANALYZE_INVARIANTS | MAGIC_SEL_ANALYZE_VIOLATIONS)) {
+        /* Analyze data first. */
+        void *value = magic_selement_to_ptr(selement);
+        sel_analyzed->type_id = MAGIC_TYPE_POINTER;
+        sel_analyzed->u.ptr.value = value;
+        ret |= MAGIC_SEL_FOUND_DATA;
+        if (value == NULL) {
+            /* Null pointer. */
+            MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_NULL_ENTRY);
+        }
+        else {
+            /* Check target. */
+            struct _magic_dsentry *trg_dsentry_ptr;
+            struct _magic_dfunction *trg_dfunction_ptr;
+            void *args_array[5];
+            if (!(flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)) {
+                trg_dsentry_ptr = &sel_analyzed->u.ptr.trg.dsentry;
+                trg_dfunction_ptr = &sel_analyzed->u.ptr.trg.dfunction;
+                args_array[0] = &trg_dsentry_ptr;
+                args_array[1] = &trg_dfunction_ptr;
+            } else {
+                args_array[0] = &sel_analyzed->u.ptr.trg_p.dsentry;
+                args_array[1] = &sel_analyzed->u.ptr.trg_p.dfunction;
+            }
+            args_array[2] = selement;
+            args_array[3] = sel_analyzed;
+            args_array[4] = &flags;
+            r = magic_type_target_walk(value, args_array[0], args_array[1],
+                magic_sentry_analyze_ptr_trg_cb, args_array);
+            if (r == MAGIC_ENOENT) {
+                MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_ENTRY_NOT_FOUND);
+                sel_analyzed->u.ptr.trg_flags = magic_range_lookup_by_addr(value, NULL);
+            }
+            else if (r == MAGIC_EBADENT) {
+                MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_BAD_ENTRY);
+                sel_analyzed->u.ptr.trg_flags = magic_range_lookup_by_addr(value, NULL);
+            }
+            else if (sel_analyzed->u.ptr.num_trg_types == 0) {
+                MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_BAD_OFFSET);
+                sel_analyzed->u.ptr.trg_flags = magic_range_lookup_by_addr(value, NULL);
+            }
+        }
+
+        if (flags & (MAGIC_SEL_ANALYZE_INVARIANTS | MAGIC_SEL_ANALYZE_VIOLATIONS)) {
+            /* Check value-based invariants. */
+            ret |= magic_selement_analyze_ptr_value_invs(selement,
+                sel_analyzed, sel_stats);
+
+            /* Check target-based invariants. */
+            if (!(ret & MAGIC_SEL_FOUND_INVARIANTS)) {
+                ret |= magic_selement_analyze_ptr_trg_invs(selement,
+                    sel_analyzed, sel_stats);
+            }
+
+            /* Check type-based invariants. */
+            if (!(ret & MAGIC_SEL_FOUND_INVARIANTS)) {
+                ret |= magic_selement_analyze_ptr_type_invs(selement,
+                    sel_analyzed, sel_stats);
+            }
+
+            assert(ret & MAGIC_SEL_FOUND_INVARIANTS);
+            sel_stats->ptr_found++;
+            if (MAGIC_SEL_STATS_HAS_VIOLATIONS(sel_stats)) {
+                ret |= MAGIC_SEL_FOUND_VIOLATIONS;
+            }
+        }
+    }
+
+    sel_analyzed->flags = ret;
+    return ret;
+}
+
+/*===========================================================================*
+ *                  magic_selement_analyze_nonptr_value_invs                 *
+ *===========================================================================*/
+PRIVATE int magic_selement_analyze_nonptr_value_invs(_magic_selement_t *selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
+{
+    const struct _magic_type* type = selement->type;
+    int i, ret = 0;
+    int value = sel_analyzed->u.nonptr.value;
+
+    if(MAGIC_STATE_FLAG(selement->sentry, MAGIC_STATE_EXTERNAL))
+        return 0;
+
+    if(MAGIC_TYPE_HAS_VALUE_SET(type)) {
+        i=0;
+        ret |= MAGIC_SEL_FOUND_INVARIANTS;
+        while(MAGIC_TYPE_HAS_VALUE(type, i)) {
+            int trg_value = MAGIC_TYPE_VALUE(type, i);
+            if(trg_value == value) {
+                sel_stats->value_found++;
+                break;
+            }
+            i++;
+        }
+        if(!MAGIC_TYPE_HAS_VALUE(type, i)) {
+            sel_stats->badvalue_found++;
+        }
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                       magic_selement_analyze_nonptr                       *
+ *===========================================================================*/
+PUBLIC int magic_selement_analyze_nonptr(_magic_selement_t *selement, int flags,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
+{
+    int ret = 0;
+
+    sel_analyzed->type_id = 0;
+    memset(&sel_analyzed->u.nonptr, 0, sizeof(sel_analyzed->u.nonptr));
+    memset(sel_stats, 0, sizeof(_magic_sel_stats_t));
+
+    if(flags & (MAGIC_SEL_ANALYZE_DATA|MAGIC_SEL_ANALYZE_INVARIANTS|MAGIC_SEL_ANALYZE_VIOLATIONS)) {
+        /* Analyze data first. */
+        switch(selement->type->type_id) {
+            case MAGIC_TYPE_VOID:
+                sel_analyzed->type_id = MAGIC_TYPE_VOID;
+                sel_analyzed->u.nonptr.value = (long) *((char*)selement->address);
+                ret |= MAGIC_SEL_FOUND_DATA;
+            break;
+
+            case MAGIC_TYPE_FLOAT:
+                sel_analyzed->type_id = MAGIC_TYPE_FLOAT;
+                sel_analyzed->u.nonptr.value = (long) magic_selement_to_float(selement);
+                ret |= MAGIC_SEL_FOUND_DATA;
+            break;
+
+            case MAGIC_TYPE_INTEGER:
+            case MAGIC_TYPE_ENUM:
+                sel_analyzed->type_id = selement->type->type_id;
+                sel_analyzed->u.nonptr.value = magic_selement_to_int(selement);
+                ret |= MAGIC_SEL_FOUND_DATA;
+                if((flags & MAGIC_SEL_ANALYZE_LIKELYPOINTERS) && selement->type->size == sizeof(void*)) {
+                    sel_analyzed->u.nonptr.trg_flags = magic_range_lookup_by_addr((void*) sel_analyzed->u.nonptr.value, NULL);
+                }
+                if(flags & (MAGIC_SEL_ANALYZE_INVARIANTS|MAGIC_SEL_ANALYZE_VIOLATIONS)) {
+                    /* Check value-based invariants. */
+                    ret |= magic_selement_analyze_nonptr_value_invs(selement,
+                        sel_analyzed, sel_stats);
+
+                    if(ret & MAGIC_SEL_FOUND_INVARIANTS) {
+                        sel_stats->nonptr_found++;
+                        if(MAGIC_SEL_STATS_HAS_VIOLATIONS(sel_stats)) {
+                            ret |= MAGIC_SEL_FOUND_VIOLATIONS;
+                        }
+                    }
+                    else {
+                        sel_stats->nonptr_unconstrained_found++;
+                    }
+                }
+            break;
+        }
+    }
+
+    sel_analyzed->flags = ret;
+    return ret;
+}
+
+/*===========================================================================*
+ *                 magic_sel_analyzed_trg_selements_print                    *
+ *===========================================================================*/
+PUBLIC void magic_sel_analyzed_trg_selements_print(_magic_sel_analyzed_t *sel_analyzed,
+    int flags)
+{
+    int num;
+    int i=0;
+    const _magic_selement_t* trg_selement;
+    _magic_trg_stats_t trg_stats;
+
+    num = sel_analyzed->u.ptr.num_trg_types;
+    if(num == 0) {
+        return;
+    }
+    _magic_printf("#%d|%d", num, sel_analyzed->u.ptr.num_legal_trg_types);
+
+    for(;i<num;i++) {
+        trg_selement = &sel_analyzed->u.ptr.trg_selements[i];
+        trg_stats = sel_analyzed->u.ptr.trg_stats[i];
+        _magic_printf("%s%d|%c=", (i==0 ? ": " : ", "), i+1, MAGIC_SEL_ANALYZED_TRG_STATS_C(trg_stats));
+        MAGIC_SELEMENT_PRINT(trg_selement, flags|MAGIC_SKIP_COMP_TYPES);
+    }
+}
+
+/*===========================================================================*
+ *                        magic_selement_type_cast                           *
+ *===========================================================================*/
+PUBLIC _magic_selement_t* magic_selement_type_cast(
+    _magic_selement_t *selement, int flags, const struct _magic_type* type,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
+{
+    _magic_sel_stats_t my_sel_stats;
+
+    selement->type = type;
+    if(sel_analyzed) {
+        magic_selement_analyze(selement, flags,
+            sel_analyzed, sel_stats ? sel_stats : &my_sel_stats);
+    }
+    return selement;
+}
+
diff --git a/minix/llvm/static/magic/magic_asr.c b/minix/llvm/static/magic/magic_asr.c
new file mode 100644 (file)
index 0000000..5c576d2
--- /dev/null
@@ -0,0 +1,129 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <magic_def.h>
+#include <magic_mem.h>
+#include <magic_asr.h>
+#include <magic.h>
+
+#ifdef __MINIX
+static unsigned long magic_rand_next;
+static void magic_srand(unsigned int seed)
+{
+    magic_rand_next = (unsigned long) seed;
+}
+
+static int magic_rand()
+{
+    magic_rand_next = magic_rand_next * 1103515245 + 12345;
+    return (int)(magic_rand_next % ((unsigned long)RAND_MAX + 1));
+}
+static int magic_rand_seed()
+{
+    int x;
+    return (int)&x + (int)&magic_rand_seed;
+}
+#else
+#define magic_srand     srand
+#define magic_rand      rand
+#define magic_rand_seed() time(0)
+#endif
+
+#define MINIMUM_PADDING 1
+
+PUBLIC int magic_asr_get_padding_size(int region) {
+    int padding = 0;
+
+    switch(region) {
+        case MAGIC_STATE_HEAP | MAGIC_ASR_FLAG_INIT:
+            if(_magic_asr_heap_max_offset){
+                padding = (magic_rand() % _magic_asr_heap_max_offset) + MINIMUM_PADDING;
+            }
+            break;
+        case MAGIC_STATE_HEAP:
+            if(_magic_asr_heap_max_padding){
+                 padding = (magic_rand() % _magic_asr_heap_max_padding) + MINIMUM_PADDING;
+            }
+            break;
+        case MAGIC_STATE_MAP | MAGIC_ASR_FLAG_INIT:
+            if(_magic_asr_map_max_offset_pages){
+                padding = ((magic_rand() % _magic_asr_map_max_offset_pages) + MINIMUM_PADDING) * magic_get_sys_pagesize();
+            }
+            break;
+        case MAGIC_STATE_MAP:
+            if(_magic_asr_map_max_padding_pages){
+                padding = ((magic_rand() % _magic_asr_map_max_padding_pages) + MINIMUM_PADDING) * magic_get_sys_pagesize();
+            }
+            break;
+        default:
+            padding = -1;
+    }
+    return padding;
+}
+
+PUBLIC void magic_asr_permute_dsentries(struct _magic_dsentry **first_dsentry_ptr){
+    struct _magic_dsentry *first_dsentry = *first_dsentry_ptr, *dsentry = first_dsentry, *last_dsentry;
+    int n_dsentries = 0;
+    int i;
+
+    if(!_magic_asr_heap_map_do_permutate){
+        /*
+         * Dsentries order is reversed anyway, because newer dsentries are
+         * placed at the start of the linked list, instead of the end
+         */
+        return;
+    }
+
+    while(dsentry != NULL){
+        last_dsentry = dsentry;
+        n_dsentries++;
+        dsentry = dsentry->next;
+    }
+
+    for(i=0; i < n_dsentries; i++){
+        int j;
+        int pos = magic_rand() % (n_dsentries - i);
+        struct _magic_dsentry *prev_dsentry = NULL;
+
+        if((i == 0) && (pos == (n_dsentries -1))){
+            /*
+             * Rest of for-loop won't function correctly when last dsentry is chosen first.
+             * Instead, nothing has to be done in this case.
+             */
+            continue;
+        }
+
+        dsentry = first_dsentry;
+
+        for(j=0;j<pos;j++){
+            prev_dsentry = dsentry;
+            dsentry = dsentry->next;
+        }
+
+        if(pos == 0){
+            first_dsentry = first_dsentry->next;
+        }else{
+            prev_dsentry->next = dsentry->next;
+        }
+
+        dsentry->next = NULL;
+        last_dsentry->next = dsentry;
+        last_dsentry = dsentry;
+    }
+    *first_dsentry_ptr = first_dsentry;
+}
+
+PUBLIC void magic_asr_init(){
+    int seed, heap_offset;
+    if(_magic_asr_seed){
+        seed = _magic_asr_seed;
+    }else{
+        seed = magic_rand_seed();
+    }
+    magic_srand(seed);
+
+    heap_offset = magic_asr_get_padding_size(MAGIC_STATE_HEAP|MAGIC_ASR_FLAG_INIT);
+    if(heap_offset){
+        sbrk(heap_offset);
+    }
+}
diff --git a/minix/llvm/static/magic/magic_eval.c b/minix/llvm/static/magic/magic_eval.c
new file mode 100644 (file)
index 0000000..469e4c5
--- /dev/null
@@ -0,0 +1,216 @@
+#include <magic_eval.h>
+#include <magic.h>
+#include <magic_eval_lib.h>
+
+#define DEBUG                           MAGIC_DEBUG_SET(0)
+
+#if DEBUG
+#define MAGIC_EVAL_PRINTF _magic_printf
+#else
+#define MAGIC_EVAL_PRINTF magic_null_printf
+#endif
+
+PRIVATE int magic_eval_print_style = MAGIC_EVAL_PRINT_STYLE_DEFAULT;
+
+/*===========================================================================*
+ *                         magic_eval_get_var_cb                             *
+ *===========================================================================*/
+PRIVATE struct val* magic_eval_get_var_cb(char* name, struct val* val)
+{
+    _magic_selement_t selement;
+    int ret;
+    double dvalue;
+    void *pvalue;
+    unsigned long uvalue;
+    long ivalue;
+    char vvalue;
+    struct _magic_dsentry dsentry_buff;
+    MAGIC_EVAL_PRINTF("magic_eval_get_var_cb: %s requested\n", name);
+    ret = magic_selement_lookup_by_name(name, &selement, &dsentry_buff);
+    if(ret < 0) {
+        return NULL;
+    }
+    val->type = T_INT;
+    switch(selement.type->type_id) {
+        case MAGIC_TYPE_FLOAT:
+            dvalue = magic_selement_to_float(&selement);
+            val->type = T_REAL;
+            val->rval = dvalue;
+        break;
+
+        case MAGIC_TYPE_POINTER:
+            pvalue = magic_selement_to_ptr(&selement);
+            val->ival = (long) pvalue;
+        break;
+
+        case MAGIC_TYPE_INTEGER:
+        case MAGIC_TYPE_ENUM:
+            if(MAGIC_TYPE_FLAG(selement.type, MAGIC_TYPE_UNSIGNED)) {
+                uvalue = magic_selement_to_unsigned(&selement);
+                val->ival = (long) uvalue;
+            }
+            else {
+                ivalue = magic_selement_to_int(&selement);
+                val->ival = ivalue;
+            }
+        break;
+
+        case MAGIC_TYPE_VOID:
+            vvalue = *((char*) selement.address);
+            val->ival = (long) vvalue;
+        break;
+
+        default:
+            return NULL;
+        break;
+    }
+
+    if(magic_eval_print_style & MAGIC_EVAL_PRINT_VAR_VALUES) {
+        if(val->type == T_INT) {
+            _magic_printf("VAR: %s = %ld\n", name, val->ival);
+        }
+        else {
+            _magic_printf("VAR: %s = %g\n", name, val->rval);
+        }
+    }
+
+    return val;
+}
+
+/*===========================================================================*
+ *                     magic_eval_get_func_result_cb                         *
+ *===========================================================================*/
+PRIVATE struct val* magic_eval_get_func_result_cb(char* name, struct val* arg,
+    struct val* ret)
+{
+    struct _magic_function *function;
+    magic_eval_func_t magic_eval_func;
+    long result, iarg;
+    MAGIC_EVAL_PRINTF("magic_eval_get_func_result_cb: %s requested\n", name);
+    if(strncmp(MAGIC_EVAL_FUNC_PREFIX, name, strlen(MAGIC_EVAL_FUNC_PREFIX))) {
+        return NULL;
+    }
+
+    function = magic_function_lookup_by_name(NULL, name);
+    if(!function) {
+        return NULL;
+    }
+    magic_eval_func = (magic_eval_func_t) (long) function->address;
+    iarg = arg->type == T_INT ? arg->ival : (long) arg->rval;
+    result = magic_eval_func(iarg);
+    ret->type = T_INT;
+    ret->ival = result;
+
+    if(magic_eval_print_style & MAGIC_EVAL_PRINT_FUNC_RESULTS) {
+        _magic_printf("FUNCTION: %s(%ld) = %ld\n", name, iarg, result);
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                             magic_eval_init                               *
+ *===========================================================================*/
+PUBLIC void magic_eval_init()
+{
+    eval_set_cb_get_var(magic_eval_get_var_cb);
+    eval_set_cb_get_func_result(magic_eval_get_func_result_cb);
+}
+
+/*===========================================================================*
+ *                               magic_eval                                  *
+ *===========================================================================*/
+PRIVATE int magic_eval(char *expr, struct val* result)
+{
+    int ret;
+    MAGIC_EVAL_PRINTF("magic_eval: Evaluating expression %s\n", expr);
+    ret = evaluate(expr, result, NULL);
+    switch(ret) {
+        case ERROR_SYNTAX:
+            ret = MAGIC_EINVAL;
+        break;
+        case ERROR_FUNCNOTFOUND:
+        case ERROR_VARNOTFOUND:
+            ret = MAGIC_ENOENT;
+        break;
+        case ERROR_NOMEM:
+            ret = MAGIC_ENOMEM;
+        break;
+        case ERROR_DIV0:
+            ret = MAGIC_EBADMSTATE;
+        break;
+        case RESULT_OK:
+            ret = 0;
+        break;
+        default:
+            ret = MAGIC_EGENERIC;
+        break;
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                             magic_eval_int                                *
+ *===========================================================================*/
+PUBLIC int magic_eval_int(char *expr, long *result)
+{
+    struct val val_res;
+    int ret;
+    ret = magic_eval(expr, &val_res);
+    if(ret < 0) {
+        return ret;
+    }
+    *result = val_res.type == T_INT ? val_res.ival : (long) val_res.rval;
+    return 0;
+}
+
+/*===========================================================================*
+ *                             magic_eval_bool                               *
+ *===========================================================================*/
+PUBLIC int magic_eval_bool(char *expr, char *result)
+{
+    struct val val_res;
+    int ret;
+    ret = magic_eval(expr, &val_res);
+    if(ret < 0) {
+        return ret;
+    }
+    if(val_res.type != T_INT) {
+        return MAGIC_EINVAL;
+    }
+    *result = val_res.ival == 0 ? 0 : 1;
+    return 0;
+}
+
+/*===========================================================================*
+ *                            magic_eval_float                               *
+ *===========================================================================*/
+PUBLIC int magic_eval_float(char *expr, double *result)
+{
+    struct val val_res;
+    int ret;
+    ret = magic_eval(expr, &val_res);
+    if(ret < 0) {
+        return ret;
+    }
+    *result = val_res.type == T_INT ? (double) val_res.ival : val_res.rval;
+    return 0;
+}
+
+/*===========================================================================*
+ *                       magic_eval_get_print_style                          *
+ *===========================================================================*/
+PUBLIC int magic_eval_get_print_style()
+{
+    return magic_eval_print_style;
+}
+
+/*===========================================================================*
+ *                       magic_eval_set_print_style                          *
+ *===========================================================================*/
+PUBLIC void magic_eval_set_print_style(int style)
+{
+    magic_eval_print_style = style;
+}
+
diff --git a/minix/llvm/static/magic/magic_eval_lib.c b/minix/llvm/static/magic/magic_eval_lib.c
new file mode 100644 (file)
index 0000000..9aa8d20
--- /dev/null
@@ -0,0 +1,1159 @@
+/* evaluate.c (C) 2000-2002 Kyzer/CSG. */
+/* Released under the terms of the GNU General Public Licence version 2. */
+
+#include "magic_eval_lib.h"
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#if USE_MATH_LIB
+#include <math.h>
+#endif
+
+/* a token structure */
+struct tok {
+    struct tok *next;
+    struct var *var;
+    char     token;
+    struct val val;
+    char     funcid, *name, *name_end;
+};
+#define REG_TOK_SIZE() offsetof(struct tok, val)
+#define VAL_TOK_SIZE() offsetof(struct tok, funcid)
+#define VAR_TOK_SIZE() sizeof(struct tok)
+
+/* private memory header for tracked memory allocation */
+struct memh {
+    struct memh *next;
+    void *ptr;
+};
+
+/* creates a new memory header for allocating memory */
+static struct memh *create_mem();
+
+/* allocates memory using a particular header */
+static void *mem_alloc(struct memh *mh, size_t len);
+
+/* frees all memory for a particular header */
+static void free_mem(struct memh *mh);
+
+/* token types */
+enum {
+    /* parentheses */
+    TK_OPEN, TK_CLOSE,
+
+    /* variables and values */
+    TK_VAR, TK_VARQUOTE, TK_VAL,
+
+    /* binary operators */
+    TK_ADD, TK_SUB, TK_MUL, TK_MULI, TK_DIV,
+    TK_MOD, TK_POW, TK_AND, TK_OR, TK_BAND,
+    TK_BOR, TK_BXOR, TK_EQ, TK_NE, TK_LT, TK_GT,
+    TK_LE, TK_GE, TK_SHL, TK_SHR,
+
+    /* unary operators */
+    TK_ASSN, TK_NEG, TK_FUNC, TK_NOT, TK_BNOT,
+
+    /* special scan codes */
+    TK_BREAK, /* finish scanning, bring remainder of string forward */
+    TK_ERROR, /* abort scanning */
+    TK_SKIP     /* ignore the character */
+};
+
+/* lookup table to do conversion [char -> token type] */
+char scantable[UCHAR_MAX+1];
+int scantable_ok = 0;
+
+/* table of function names */
+char *functable[] = {
+    "acos", "asin", "atan", "cos", "cosh", "exp", "ln", "log",
+    "sin", "sinh", "sqr", "sqrt", "tan", "tanh", NULL
+};
+
+/* function ids (index to functable) */
+enum {
+    F_ACOS, F_ASIN, F_ATAN, F_COS, F_COSH, F_EXP, F_LN, F_LOG,
+    F_SIN, F_SINH, F_SQR, F_SQRT, F_TAN, F_TANH
+};
+
+/* callbacks */
+static get_var_cb_t get_var_cb = NULL;
+static get_func_result_cb_t get_func_result_cb = NULL;
+void eval_set_cb_get_var(get_var_cb_t cb) {
+        get_var_cb = cb;
+}
+void eval_set_cb_get_func_result(get_func_result_cb_t cb) {
+        get_func_result_cb = cb;
+}
+
+int same_str(const char *a, const char *b);
+int same_str_len(const char *a, const char *b, int len);
+
+void init_scantable();
+int tokenize(struct memh *mh, char **string, struct tok **listptr);
+int scan_number(char **stringptr, struct val *valptr);
+int precedence(struct tok *t);
+int eval(struct memh *mh, struct tok *list, struct vartable *vt,
+    struct val *result);
+void prt_lst(struct tok *t);
+void prt_tok(struct tok *t);
+
+/*** FRONT-END ***/
+
+int evaluate(char *expr, struct val *result, struct vartable *vartable) {
+    struct memh *mh = NULL;
+    int error = RESULT_OK, madevar = 0;
+    struct tok *list;
+    char *str;
+
+    /* ensure we have a variable table */
+    if (!vartable) madevar = 1, vartable = create_vartable();
+    if (!vartable) return ERROR_NOMEM;
+
+    init_scantable();
+    result->type = T_INT;
+    result->ival = 0;
+
+    if ((mh = create_mem())) {
+        if (expr && (str = (char *) mem_alloc(mh, strlen(expr)+1))) {
+            strcpy(str, expr);
+            while (*str) {
+    if ((error = tokenize(mh, &str, &list)) != RESULT_OK) break;
+    if ((error = eval(mh, list, vartable, result)) != RESULT_OK) break;
+            }
+        } else error = ERROR_NOMEM;
+    } else error = ERROR_NOMEM;
+
+    if(mh) free_mem(mh);
+    if (madevar) free_vartable(vartable);
+    return error;
+}
+
+
+
+
+/**** TOKENIZATION ***/
+
+void init_scantable() {
+    int i;
+
+    if (scantable_ok) return;
+
+    for (i = 0; i <= UCHAR_MAX; i++)
+        scantable[i] =
+            (isalpha(i) || i == '_') ? TK_VAR :
+         (isdigit(i) ? TK_VAL :
+         (isspace(i) ? TK_SKIP :
+                                     TK_ERROR));
+
+    scantable['+'] = TK_ADD;
+    scantable['-'] = TK_SUB;
+    scantable['*'] = TK_MUL;    /* also '**' = TK_POW */
+    scantable['/'] = TK_DIV;
+    scantable['%'] = TK_MOD;
+    scantable['$'] = TK_VAL;    /* '$' starts a hexadecimal value */
+    scantable['.'] = TK_VAL;    /* '.' starts a fractional value */
+    scantable['('] = TK_OPEN;
+    scantable[')'] = TK_CLOSE;
+    scantable[';'] = TK_BREAK;
+    scantable['='] = TK_ASSN; /* also '==' = TK_EQ */
+    scantable['~'] = TK_BNOT;
+    scantable['^'] = TK_BXOR;
+    scantable['&'] = TK_BAND; /* also '&&' = TK_AND */
+    scantable['|'] = TK_BOR;    /* also '||' = TK_OR */
+    scantable['!'] = TK_NOT;    /* also '!=' = TK_NE */
+    scantable['<'] = TK_LT;     /* also '<<' = TK_SHL, '<=' = TK_LE */
+    scantable['>'] = TK_GT;     /* also '>>' = TK_SHR, '>=' = TK_GE */
+    scantable['\''] = TK_VARQUOTE;
+
+    scantable_ok = 1;
+}
+
+#if !MEM_LOW_FOOTPRINT
+
+int tokenize(struct memh *mh, char **string, struct tok **listptr) {
+    struct tok *list;
+    int idx = 0, i, len;
+    char *s, *name, c, c2, nt;
+
+    /* allocate a block of memory to hold the maximum amount of tokens */
+    i = strlen(*string) + 1;
+    list = (struct tok *) mem_alloc(mh, i * sizeof(struct tok));
+    if (!list) return ERROR_NOMEM;
+
+    for (s = *string; *s; s++) {
+        /* get token type of character and store into list */
+        c = list[idx].token = scantable[* (unsigned char *) s];
+
+#if TOKEN_DEBUG
+         printf("tokenize: token %p code %d string %s\n", &list[idx], list[idx].token, s);
+#endif
+
+        /* break out of the for loop on TK_BREAK */
+        if (c == TK_BREAK) { s++; break; }
+
+        switch (c) {
+        case TK_ERROR:
+            return ERROR_SYNTAX;
+
+        case TK_SKIP:
+            break;
+
+        /* most symbol-tokens fall under this one - nothing much to do */
+        case TK_OPEN: case TK_CLOSE: case TK_ADD: case TK_SUB:
+        case TK_MUL: case TK_DIV: case TK_MOD: case TK_BAND: case TK_BOR:
+        case TK_BXOR: case TK_BNOT: case TK_NOT: case TK_LT: case TK_GT:
+
+            /* check for 'double character' tokens */
+            c2 = s[1];
+            nt = 0;
+            if (c == TK_MUL  && c2 == '*') nt = TK_POW;
+            if (c == TK_BAND && c2 == '&') nt = TK_AND;
+            if (c == TK_BOR  && c2 == '|') nt = TK_OR;
+            if (c == TK_NOT  && c2 == '=') nt = TK_NE;
+            if (c == TK_LT   && c2 == '=') nt = TK_LE;
+            if (c == TK_LT   && c2 == '<') nt = TK_SHL;
+            if (c == TK_GT   && c2 == '=') nt = TK_GE;
+            if (c == TK_GT   && c2 == '>') nt = TK_SHR;
+            if (nt) { list[idx].token = nt; s++; }
+
+            idx++;
+            break;
+
+        case TK_ASSN:
+            /* '=' = TK_ASSN, '==' = TK_EQ */
+            if (s[1] == '=') { list[idx++].token = TK_EQ; s++; break; }
+
+            /* if the last token was a variable, change it to an assignment */
+            if (idx <= 0 || list[idx-1].token != TK_VAR) return ERROR_SYNTAX;
+            list[idx-1].token = TK_ASSN;
+            break;
+
+        case TK_VAL:
+            if (!scan_number(&s, &list[idx++].val)) return ERROR_SYNTAX;
+            s--; /* wind back one for the loop's iterator */
+            break;
+
+        case TK_VAR:
+        case TK_VARQUOTE:
+            if(c == TK_VAR) {
+                    list[idx].name = name = s;
+                    c2 = scantable[(int)s[1]];
+                    while (c2 == TK_VAR || c2 == TK_VAL) {
+                            s++; /* skip to end of string */
+                            c2 = scantable[(int)s[1]];
+                    }
+            }
+            else {
+                    if(!s[1] || scantable[(int)s[1]] == TK_VARQUOTE) {
+                            return ERROR_SYNTAX;
+                    }
+                    list[idx].token = TK_VAR;
+                    list[idx].name = name = ++s;
+                    while (s[1] && scantable[(int)s[1]] != TK_VARQUOTE) s++; /* skip to end of string */
+                    if(!s[1]) {
+                            return ERROR_SYNTAX;
+                    }
+            }
+            list[idx].name_end = s+1;
+            len = s+1 - name;
+            if(c == TK_VARQUOTE) {
+                    s++;
+            }
+
+            if(scantable[(int)s[1]] == TK_OPEN) {
+                    list[idx].token  = TK_FUNC;
+                    list[idx].funcid = 0;
+                    /* look for matching function */
+                    for (i = 0; functable[i]; i++) {
+                        char *fname = functable[i];
+                        if (same_str_len(name, fname, len) && strlen(fname) == len) {
+                            list[idx].funcid = i+1;
+                            break;
+                        }
+                    }
+            }
+            idx++;
+            break;
+        }
+    }
+
+    /* write back the final position of the tokenizer - either pointing at
+     * a null character, or the next expression to go */
+    *string = s;
+
+    /* lace up the tokens and null-terminate the strings */
+    if (idx > 0) {
+        for (i = 0; i < idx; i++) {
+            list[i].next = &list[i+1];
+#if TOKEN_DEBUG
+            printf("tokenize: processed token %p code %d\n", &list[i], list[i].token);
+#endif
+            if (list[i].token == TK_VAR || list[i].token == TK_ASSN || list[i].token == TK_FUNC)
+                *(list[i].name_end) = '\0';
+        }
+        list[idx-1].next = NULL;
+        *listptr = list;
+    }
+    else {
+        *listptr = NULL;
+    }
+
+    return RESULT_OK;
+}
+
+#else
+
+int tokenize(struct memh *mh, char **string, struct tok **listptr) {
+    struct tok *tok = NULL, *last_tok = NULL;
+    int idx = 0, i, len;
+    char *s, *name, c, c2, nt;
+    int skip_alloc = 0;
+
+    for (s = *string; *s; s++) {
+        /* get token type of character and store into list */
+        c = scantable[* (unsigned char *) s];
+
+        /* break out of the for loop on TK_BREAK */
+        if(c == TK_BREAK) { s++; break; }
+        if(c == TK_ERROR) return ERROR_SYNTAX;
+
+        if(c == TK_SKIP) continue;
+
+        if(!skip_alloc) {
+                size_t tok_size;
+                last_tok = tok;
+                switch(c) {
+                        case TK_VAL:
+                                tok_size = VAL_TOK_SIZE();
+                        break;
+                        case TK_VAR:
+                        case TK_VARQUOTE:
+                        case TK_ASSN:
+                                tok_size = VAR_TOK_SIZE();
+                        break;
+                        default:
+                                tok_size = REG_TOK_SIZE();
+                        break;
+                }
+                tok = (struct tok *) mem_alloc(mh, tok_size);
+                if(!tok) return ERROR_NOMEM;
+                tok->next = NULL;
+                if(last_tok) {
+                        last_tok->next = tok;
+                }
+                else {
+                        *listptr = tok;
+                }
+        }
+        else {
+                skip_alloc = 0;
+        }
+        tok->token = c;
+
+#if TOKEN_DEBUG
+        printf("tokenize: token %p code %d string %s\n", tok, tok->token, s);
+#endif
+
+        switch (c) {
+
+        /* most symbol-tokens fall under this one - nothing much to do */
+        case TK_OPEN: case TK_CLOSE: case TK_ADD: case TK_SUB:
+        case TK_MUL: case TK_DIV: case TK_MOD: case TK_BAND: case TK_BOR:
+        case TK_BXOR: case TK_BNOT: case TK_NOT: case TK_LT: case TK_GT:
+
+            /* check for 'double character' tokens */
+            c2 = s[1];
+            nt = 0;
+            if (c == TK_MUL  && c2 == '*') nt = TK_POW;
+            if (c == TK_BAND && c2 == '&') nt = TK_AND;
+            if (c == TK_BOR  && c2 == '|') nt = TK_OR;
+            if (c == TK_NOT  && c2 == '=') nt = TK_NE;
+            if (c == TK_LT   && c2 == '=') nt = TK_LE;
+            if (c == TK_LT   && c2 == '<') nt = TK_SHL;
+            if (c == TK_GT   && c2 == '=') nt = TK_GE;
+            if (c == TK_GT   && c2 == '>') nt = TK_SHR;
+            if (nt) { tok->token = nt; s++; }
+
+            idx++;
+            break;
+
+        case TK_ASSN:
+            /* '=' = TK_ASSN, '==' = TK_EQ */
+            if (s[1] == '=') { tok->token = TK_EQ; idx++; s++; break; }
+
+            /* if the last token was a variable, change it to an assignment */
+            if (idx <= 0 || last_tok->token != TK_VAR) return ERROR_SYNTAX;
+            last_tok->token = TK_ASSN;
+            skip_alloc = 1;
+            break;
+
+        case TK_VAL:
+            if (!scan_number(&s, &tok->val)) return ERROR_SYNTAX;
+            idx++;
+            s--; /* wind back one for the loop's iterator */
+            break;
+
+        case TK_VAR:
+        case TK_VARQUOTE:
+            if(c == TK_VAR) {
+                    tok->name = name = s;
+                    c2 = scantable[(int)s[1]];
+                    while (c2 == TK_VAR || c2 == TK_VAL) {
+                            s++; /* skip to end of string */
+                            c2 = scantable[(int)s[1]];
+                    }
+            }
+            else {
+                    if(!s[1] || scantable[(int)s[1]] == TK_VARQUOTE) {
+                            return ERROR_SYNTAX;
+                    }
+                    tok->token = TK_VAR;
+                    tok->name = name = ++s;
+                    while (s[1] && scantable[(int)s[1]] != TK_VARQUOTE) s++; /* skip to end of string */
+                    if(!s[1]) {
+                            return ERROR_SYNTAX;
+                    }
+            }
+            tok->name_end = s+1;
+            len = s+1 - name;
+            if(c == TK_VARQUOTE) {
+                    s++;
+            }
+
+            if(scantable[(int)s[1]] == TK_OPEN) {
+                    tok->token  = TK_FUNC;
+                    tok->funcid = 0;
+                    /* look for matching function */
+                    for (i = 0; functable[i]; i++) {
+                        char *fname = functable[i];
+                        if (same_str_len(name, fname, len) && strlen(fname) == len) {
+                            tok->funcid = i+1;
+                            break;
+                        }
+                    }
+            }
+            idx++;
+            break;
+        }
+    }
+
+    /* write back the final position of the tokenizer - either pointing at
+     * a null character, or the next expression to go */
+    *string = s;
+
+    /* lace up the tokens and null-terminate the strings */
+    if (idx > 0) {
+        tok = *listptr;
+        do {
+#if TOKEN_DEBUG
+            printf("tokenize: processed token %p code %d\n", tok, tok->token);
+#endif
+            if (tok->token == TK_VAR || tok->token == TK_ASSN || tok->token == TK_FUNC)
+                *(tok->name_end) = '\0';
+            tok = tok->next;
+        } while(tok);
+    }
+    else {
+        *listptr = NULL;
+    }
+
+    return RESULT_OK;
+}
+
+#endif
+
+/* scans some text into a value */
+int scan_number(char **stringptr, struct val *valptr) {
+    struct val v = { T_INT, 0, 0.0 };
+    char *s = *stringptr;
+    int c;
+    double dp;
+
+    /* test to see if it's a hex number */
+    if (s[0] == '$' || (s[0] == '0' && s[1] == 'x')) {
+        s += (s[1] == 'x') ? 2 : 1;
+        *stringptr = s;
+
+        for (; isxdigit(c = (int) *s); s++)
+            v.ival = (v.ival << 4)
+                + (isdigit(c) ? c-'0'            : 0)
+                + (isupper(c) ? c-'A' + 10 : 0)
+                + (islower(c) ? c-'a' + 10 : 0);
+    }
+
+    /* must be a decimal integer or real */
+    else {
+        for (; isdigit(c = (int) *s); s++) v.ival = (v.ival * 10) + c-'0';
+        if (*s == '.') {
+            *stringptr = ++s;
+            v.type = T_REAL;
+            v.rval = (double) v.ival;
+            for (dp = 0.1; isdigit(c = (int) *s); s++, dp /= 10.0)
+                v.rval += dp * (double) (c-'0');
+        }
+    }
+
+    /* if no numeric chars have been read, it's a dud - return FAIL */
+    if (s == *stringptr) return 0;
+
+    /* otherwise, update position and return SUCCESS */
+    *stringptr = s;
+    *valptr = v;
+    return 1;
+}
+
+
+/*** EVALUATION ***/
+
+/* returns the precedence of a token */
+int precedence(struct tok *t) {
+    switch (t->token) {
+    case TK_FUNC:                                                                                                   return 15;
+    case TK_MULI:                           return 14;
+    case TK_NEG:    case TK_NOT:    case TK_BNOT:           return 13;
+    case TK_POW:                            return 12;
+    case TK_MUL:    case TK_DIV:    case TK_MOD:            return 11;
+    case TK_ADD:    case TK_SUB:                    return 10;
+    case TK_SHL:    case TK_SHR:                    return 9;
+    case TK_LT: case TK_GT: case TK_LE: case TK_GE: return 8;
+    case TK_EQ: case TK_NE:                 return 7;
+    case TK_BAND:                           return 6;
+    case TK_BOR:    case TK_BXOR:                   return 5;
+    case TK_AND:    case TK_OR:                 return 4;
+    case TK_ASSN:                           return 3;
+    case TK_CLOSE:                                  return 2;
+    case TK_OPEN:                           return 1;
+    }
+    return 0;
+}
+
+
+int eval(struct memh *mh, struct tok *list, struct vartable *vt,
+    struct val *result) {
+
+    static struct val newval = { T_INT, 0, 0.0 };
+
+    struct val tmp_val, *valstk, *x, *y;
+    struct tok open, close, *l, *r, *t, **opstk;
+    char lt, rt, token;
+    int vstk, ostk, vcnt = 0, ocnt = 0;
+    double xr, yr, rr = 0;
+    long xi, yi, ri = 0;
+#if VAR_FROM_ENV
+    char *envtxt;
+#endif
+
+    /* clear result before we do anything - and no tokens is no result */
+    *result = newval;
+    if (!list) return RESULT_OK;
+
+
+    /* CONVERSION OF RAW TOKENS INTO COMPLETE INFIX EXPRESSION */
+
+    /* wrap the token list in a pair of parentheses */
+    for (t = list; t->next; t = t->next)
+            ;
+    t->next = &close;
+    close.next = NULL; open.next = list; list = &open;
+    close.token = TK_CLOSE; open.token  = TK_OPEN;
+
+    /* insert and change tokens as neccessary */
+    for (l=list, r=l->next; r->next; l=r, r=r->next) {
+        lt = l->token;
+        rt = r->token;
+
+        /* convert TK_SUBs that should be unary into TK_NEGs */
+        if (rt == TK_SUB && lt != TK_CLOSE && lt != TK_VAR && lt != TK_VAL)
+            r->token = TK_NEG;
+
+        /* insert implicit multiplication tokens */
+        if ((lt == TK_VAR || lt == TK_VAL || lt == TK_CLOSE)
+        && (rt == TK_VAR || rt == TK_VAL || rt == TK_OPEN || rt == TK_FUNC)) {
+            if (lt == rt) return ERROR_SYNTAX;
+            t = (struct tok *) mem_alloc(mh, sizeof(struct tok));
+            if (!t) return ERROR_NOMEM;
+            t->token = TK_MULI; l->next = t; t->next = r;
+        }
+    }
+
+    /* VARIABLE CHECKING */
+
+    vcnt = ocnt = 0;
+    for (t = list; t; t = t->next) {
+        lt = t->token;
+
+        /* count the number of values and operators */
+        if (lt == TK_VAR || lt == TK_VAL) vcnt++; else ocnt++;
+
+        /* if assigned variables don't exist, create a new blank one */
+        if (lt == TK_ASSN) {
+            if (!(t->var = get_var(vt, t->name)))
+                if (!(t->var = put_var(vt, t->name, &newval)))
+                    return ERROR_NOMEM;
+        }
+
+        /* try to get vars from vartable - if not, try the environment */
+        else if (lt == TK_VAR) {
+            int var_found = 0;
+            if ((t->var = get_var(vt, t->name))) {
+                    var_found = 1;
+            }
+#if VAR_FROM_ENV
+            if(!var_found && (envtxt = getenv(t->name))) {
+                    if (!scan_number(&envtxt, &tmp_val)) return ERROR_SYNTAX;
+                    if (!(t->var = put_var(vt, t->name, &tmp_val))) return ERROR_NOMEM;
+                    var_found = 1;
+            }
+#endif
+            if(!var_found && get_var_cb && (get_var_cb(t->name, &tmp_val))) {
+                    if (!(t->var = put_var(vt, t->name, &tmp_val))) return ERROR_NOMEM;
+                    var_found = 1;
+            }
+            if(!var_found) {
+                    return ERROR_VARNOTFOUND;
+            }
+        }
+    }
+
+    /* ALLOCATE STACKS */
+
+    /* allocate the operator stack and the value stack */
+    valstk = (struct val *)  mem_alloc(mh, vcnt * sizeof(struct val));
+    opstk  = (struct tok **) mem_alloc(mh, ocnt * sizeof(struct tok *));
+    if (!valstk || !opstk) return ERROR_NOMEM;
+
+    /* set the stack pointers to '0 items on stack' */
+    /* (the stack pointers are always set at the topmost stack item) */
+    ostk = vstk = -1;
+
+    /* MAIN EVALUATION LOOP */
+    prt_lst(list);
+    for (t = list; t; t=t->next) {
+        switch (t->token) {
+
+        /* unary operators always wait until after what follows is evaluated */
+        /* also, open parentheses are pushed to match where close ones stop */
+        case TK_OPEN:
+        case TK_ASSN: case TK_NEG: case TK_FUNC: case TK_NOT: case TK_BNOT:
+            opstk[++ostk] = t; break;
+
+        /* values go straight on the value stack */
+        case TK_VAL:
+            valstk[++vstk] = t->val;
+            break;
+
+        /* variables go straight on the value stack */
+        case TK_VAR:
+            valstk[++vstk] = t->var->val;
+            break;
+
+        /* this is where the action happens - all operations of a higher or same
+         * precedence are now executed. then, after that, we push the operator
+         * to the stack, or if it's a close paren, pull and expect an open paren
+         *
+         * it's assumed that all tokens in the token stream that aren't one of
+         * the previous cases must be the close bracket or a binary operator -
+         * that's why 'default' is used rather than all the names
+         */
+        default:
+            while (precedence(opstk[ostk]) >= precedence(t)) {
+                struct tok *op = opstk[ostk--];
+#if EVAL_DEBUG
+                printf("eval: "); prt_tok(op); printf("\n");
+#endif
+
+                /* there should always be at least a close bracket left here */
+                if (ostk < 0) return ERROR_SYNTAX;
+
+                /* we assume that all operators require at least one value */
+                /* on the stack, and check here */
+                if (vstk < 0) return ERROR_SYNTAX;
+
+                /* now we actually perform evaluations */
+                switch (token = op->token) {
+
+                /* binary (int/real) -> (int/real) */
+                case TK_ADD: case TK_SUB: case TK_MUL: case TK_MULI:
+
+                    /* pull two values from the stack, y then x, and push 'x op y' */
+                    if (vstk < 1) return ERROR_SYNTAX;
+                    y = &valstk[vstk--]; x = &valstk[vstk];
+
+                    /* if both values are integer, do integer operations only */
+                    if (x->type == T_INT && y->type == T_INT) {
+                        xi = x->ival;
+                        yi = y->ival;
+                        switch (token) {
+                        case TK_MULI:
+                        case TK_MUL: ri = (xi * yi); break;
+                        case TK_ADD: ri = (xi + yi); break;
+                        case TK_SUB: ri = (xi - yi); break;
+                        }
+                        /* push int-value result to value stack */
+                        x->type = T_INT;
+                        x->ival = ri;
+                    }
+                    else {
+                        /* get real values - convert if neccessary */
+                        xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
+                        yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
+
+                        switch (token) {
+                        case TK_MULI:
+                        case TK_MUL: rr = (xr * yr); break;
+                        case TK_ADD: rr = (xr + yr); break;
+                        case TK_SUB: rr = (xr - yr); break;
+                        }
+                        /* push real-value result to value stack */
+                        x->type = T_REAL;
+                        x->rval = rr;
+                    }
+                    break;
+
+
+
+                /* binary (int/real) -> int */
+                case TK_EQ: case TK_NE: case TK_LT:
+                case TK_GT: case TK_LE: case TK_GE:
+
+                    if (vstk < 1) return ERROR_SYNTAX;
+                    y = &valstk[vstk--]; x = &valstk[vstk];
+
+                    if (x->type == T_INT && y->type == T_INT) {
+                        xi = x->ival;
+                        yi = y->ival;
+                        switch (token) {
+                        case TK_EQ:  ri = (xi == yi); break;
+                        case TK_NE:  ri = (xi != yi); break;
+                        case TK_LT:  ri = (xi <  yi); break;
+                        case TK_GT:  ri = (xi >  yi); break;
+                        case TK_LE:  ri = (xi <= yi); break;
+                        case TK_GE:  ri = (xi >= yi); break;
+                        }
+                    }
+                    else {
+                        xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
+                        yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
+                        switch (token) {
+                        case TK_EQ:  ri = (xr == yr); break;
+                        case TK_NE:  ri = (xr != yr); break;
+                        case TK_LT:  ri = (xr <  yr); break;
+                        case TK_GT:  ri = (xr >  yr); break;
+                        case TK_LE:  ri = (xr <= yr); break;
+                        case TK_GE:  ri = (xr >= yr); break;
+                        }
+                    }
+                    x->type = T_INT;
+                    x->ival = ri;
+                    break;
+
+
+                /* binary real -> real */
+                case TK_DIV: case TK_POW:
+
+                    if (vstk < 1) return ERROR_SYNTAX;
+                    y = &valstk[vstk--]; x = &valstk[vstk];
+                    xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
+                    yr = (y->type == T_REAL) ? y->rval : (double) y->ival;
+
+                    if (token == TK_DIV) {
+                        if (yr == 0) return ERROR_DIV0;
+                        x->rval = xr / yr;
+                    }
+                    else {
+#if USE_MATH_LIB
+                        x->rval = pow(xr, yr);
+#else
+                        x->rval = 0;
+#endif
+                    }
+                    x->type = T_REAL;
+        break;
+
+
+                /* binary int -> int */
+                case TK_MOD: case TK_AND: case TK_OR:
+                case TK_BAND: case TK_BOR: case TK_BXOR:
+                case TK_SHL: case TK_SHR:
+
+                    if (vstk < 1) return ERROR_SYNTAX;
+                    y = &valstk[vstk--]; x = &valstk[vstk];
+                    xi = (x->type == T_INT) ? x->ival : (long) x->rval;
+                    yi = (y->type == T_INT) ? y->ival : (long) y->rval;
+
+                    switch (token) {
+                    case TK_MOD:    if (yi == 0) return ERROR_DIV0;
+                                                ri = (xi %  yi); break;
+                    case TK_AND:    ri = (xi && yi); break;
+                    case TK_OR:     ri = (xi || yi); break;
+                    case TK_BAND: ri = (xi &    yi); break;
+                    case TK_BOR:    ri = (xi |  yi); break;
+                    case TK_BXOR: ri = (xi ^    yi); break;
+                    case TK_SHL:    ri = (xi << yi); break;
+                    case TK_SHR:    ri = (xi >> yi); break;
+                    }
+
+                    x->type = T_INT;
+                    x->ival = ri;
+                    break;
+
+
+
+                /* unary real -> real */
+                case TK_FUNC:
+                    x = &valstk[vstk];
+                    if(op->funcid) {
+#if USE_MATH_LIB
+                            xr = (x->type == T_REAL) ? x->rval : (double) x->ival;
+                            switch (op->funcid-1) {
+                            case F_ACOS: xr =  acos(xr); break;
+                            case F_ASIN: xr =  asin(xr); break;
+                            case F_ATAN: xr =  atan(xr); break;
+                            case F_COS:  xr =       cos(xr); break;
+                            case F_COSH: xr =  cosh(xr); break;
+                            case F_EXP:  xr =       exp(xr); break;
+                            case F_LN:   xr =       log(xr); break;
+                            case F_LOG:  xr = log10(xr); break;
+                            case F_SIN:  xr =       sin(xr); break;
+                            case F_SINH: xr =  sinh(xr); break;
+                            case F_SQR:  xr =       xr * xr; break;
+                            case F_SQRT: xr =  sqrt(xr); break;
+                            case F_TAN:  xr =       tan(xr); break;
+                            case F_TANH: xr =  tanh(xr); break;
+                            default:         xr = 0;                 break;
+                            }
+#else
+                            xr = 0;
+#endif
+                            x->rval = xr;
+                            x->type = T_REAL;
+                    }
+                    else {
+                            if(!get_func_result_cb || !get_func_result_cb(op->name, x, x)) {
+                                    return ERROR_FUNCNOTFOUND;
+                            }
+                    }
+                    break;
+
+
+                /* unary int -> int */
+                case TK_BNOT: case TK_NOT:
+
+                    x = &valstk[vstk];
+                    xi = (x->type == T_INT) ? x->ival : (long) x->rval;
+                    if (token == TK_BNOT) {
+                        x->ival = ~ xi;
+                    }
+                    else {
+                        x->ival = ! xi;
+                    }
+                    x->type = T_INT;
+                    break;
+
+
+                /* unary (int/real) -> (int/real) */
+                case TK_ASSN:
+                    op->var->val = valstk[vstk];
+                    break;
+
+
+                /* unary (int/real) -> (int/real) */
+                case TK_NEG:
+                    x = &valstk[vstk];
+                    if (x->type == T_INT)
+                        x->ival = - x->ival;
+                    else
+                        x->rval = - x->rval;
+                    break;
+
+                } /* end select (execution switch) */
+            } /* end while (precedence loop) */
+
+            /* back to the postfixified */
+
+            /* if we had a close paren, pull the matching open paren (error if
+             * we pull something else. otherwise push our new operator
+             */
+            if (t->token == TK_CLOSE) {
+                if (opstk[ostk--]->token != TK_OPEN) return ERROR_SYNTAX;
+            }
+            else {
+                opstk[++ostk] = t;
+            }
+        }
+    }
+
+    /* there should be exactly one value and no operators left on the stacks */
+    if (vstk != 0 || ostk != -1) return ERROR_SYNTAX;
+
+    /* return that value */
+    *result = valstk[0];
+    return RESULT_OK;
+}
+
+
+
+
+
+/** debugging things **/
+#if EVAL_DEBUG
+/* expression printer */
+void prt_tok(struct tok *t) {
+    switch(t->token)    {
+    case TK_OPEN:  printf("( ");    break;
+    case TK_CLOSE: printf(") ");    break;
+
+    case TK_ADD:     printf("+ ");  break;
+    case TK_SUB:     printf("- ");  break;
+    case TK_MUL:     printf("* ");  break;
+    case TK_MULI:  printf("*i "); break;
+    case TK_POW:     printf("** "); break;
+    case TK_DIV:     printf("/ ");  break;
+    case TK_MOD:     printf("%% "); break;
+
+    case TK_EQ:      printf("== "); break;
+    case TK_NE:      printf("!= "); break;
+    case TK_LT:      printf("< ");  break;
+    case TK_GT:      printf("> ");  break;
+    case TK_LE:      printf("<= "); break;
+    case TK_GE:      printf(">= "); break;
+
+    case TK_AND:     printf("&& "); break;
+    case TK_BAND:  printf("& ");    break;
+    case TK_BNOT:  printf("~ ");    break;
+    case TK_BOR:     printf("| ");  break;
+    case TK_BXOR:  printf("^ ");    break;
+    case TK_NEG:     printf("_ ");  break;
+    case TK_NOT:     printf("! ");  break;
+    case TK_OR:      printf("|| "); break;
+    case TK_SHL:     printf("<< "); break;
+    case TK_SHR:     printf(">> "); break;
+
+    case TK_ASSN:  printf("%s = ", t->name); break;
+    case TK_FUNC:  printf("%s() ", t->funcid ? functable[(int)t->funcid-1] : t->name); break;
+    case TK_VAL:     if (t->val.type == T_INT)
+                                     printf("%ld ", t->val.ival);
+                                 else
+                                     printf("%g ", t->val.rval);
+                                 break;
+
+    case TK_VAR:     printf("%s ", t->name); break;
+    default:             printf("?? (%d)", t->token); break;
+    }
+}
+
+void prt_stk(struct tok *stk, int depth) {
+    do { prt_tok(&stk[depth]); } while (depth-- > 0);
+    printf("\n");
+}
+
+void prt_lst(struct tok *t) {
+    for (; t; t=t->next) prt_tok(t);
+    printf("\n");
+}
+
+/* variables dumper */
+void dump_vars(struct vartable *vt) {
+    struct var *v;
+    if (!vt) printf("no vars\n");
+    else for (v=vt->first; v; v=v->next) {
+        if (v->val.type == T_INT)
+            printf("'%s'=%ld ", v->name, v->val.ival);
+        else
+            printf("'%s'=%g ", v->name, v->val.rval);
+    }
+    printf("\n");
+}
+#else
+void prt_tok(struct tok *t) {}
+void prt_stk(struct tok *stk, int depth) {}
+void prt_lst(struct tok *t) {}
+void dump_vars(struct vartable *vt) {}
+#endif
+
+
+
+/*** UTILITY FUNCTIONS ***/
+
+/* case-insensitive string comparison, TRUE or FALSE result */
+int same_str(const char *a, const char *b) {
+    if (!a || !b) return 0; /* false even if a == b == null */
+    if (a == b) return 1;
+
+#ifdef HAVE_STRCASECMP
+    return (strcasecmp(a, b) == 0);
+#elif HAVE_STRCMPI
+    return (strcmpi(a, b) == 0);
+#else
+    while ((tolower((int)*a) == tolower((int)*b))) {
+        if (!*a) return 1; /* if end of both strings, return true */
+        a++; b++;
+    }
+    return 0; /* mismatch before end of string - return false */
+#endif
+}
+
+/* case-insensitive string comparison with maximum length */
+int same_str_len(const char *a, const char *b, int len) {
+    if (!a || !b) return 0; /* false even if a == b == null */
+    if (len == 0) return 0;
+    if (a == b) return 1;
+
+#ifdef HAVE_STRNCASECMP
+    return (strncasecmp(a, b, len) == 0);
+#elif HAVE_STRNCMPI
+    return (strncmpi(a, b) == 0);
+#else
+    while (--len && (tolower((int)*a) == tolower((int)*b))) {
+        if (!*a) return 1; /* true if both strings equal & end before len */
+        a++; b++;
+    }
+    /* result based on last char of allowed length */
+    return (tolower((int)*a) == tolower((int)*b)) ? 1 : 0;
+#endif
+}
+
+#if EVAL_MALLOC
+/* tracked memory allocation - create header */
+struct memh *create_mem() {
+    struct memh *mh = (struct memh *) malloc(sizeof(struct memh));
+    mh->next = NULL;
+    mh->ptr  = NULL;
+    return mh;
+}
+
+/* tracked memory allocation - allocate memory using header */
+void *mem_alloc(struct memh *mh, size_t len) {
+    struct memh *mem = (struct memh *) malloc(len + sizeof(struct memh));
+    if (!mem) return NULL;
+    mem->next = mh->next;
+    mh->next = mem;
+    return mem->ptr = (void *) &mem[1];
+}
+
+/* tracked memory allocation - free all memory in header */
+void free_mem(struct memh *mh) {
+    struct memh *next;
+    for (; mh; mh = next) {
+        next = mh->next;
+        free(mh);
+    }
+}
+
+#else
+#define MEM_BUFFER_LEN  4096
+#define MAX_NUM_BUFFERS 2
+char mem_buffer[MAX_NUM_BUFFERS][MEM_BUFFER_LEN];
+struct memh mem_headers[MAX_NUM_BUFFERS];
+int mem_idx[MAX_NUM_BUFFERS] = {0};
+
+#define MEM_HEADER_TO_N(H) ((H)-mem_headers)
+
+struct memh *create_mem() {
+    int n;
+    struct memh *mh;
+    for(n=0;n<MAX_NUM_BUFFERS;n++) {
+            if(mem_idx[n] == 0) {
+                    mem_idx[n] = 1;
+                    break;
+            }
+    }
+
+    if(n == MAX_NUM_BUFFERS) {
+#if MEM_DEBUG
+            printf("create_mem: out of buffers\n", n);
+#endif
+            return NULL;
+    }
+#if MEM_DEBUG
+    printf("create_mem: n is %d\n", n);
+#endif
+    mh = &mem_headers[n];
+    memset(mh, 0, sizeof(struct memh));
+    return mh;
+}
+
+void *mem_alloc(struct memh *mh, size_t len) {
+    int n = MEM_HEADER_TO_N(mh);
+    int mem_idx_n;
+    struct memh *mem = NULL;
+    len += sizeof(struct memh);
+    mem_idx_n = mem_idx[n]-1;
+#if MEM_DEBUG
+    printf("mem_alloc: len is %d, buffer num is %d, buffer idx is %d, buffer len is %d\n", len, n, mem_idx_n, MEM_BUFFER_LEN);
+#endif
+    if(mem_idx_n + len > MEM_BUFFER_LEN) {
+#if MEM_DEBUG
+            printf("mem_alloc: out of mem\n");
+#endif
+            return NULL;
+    }
+    mem = (struct memh *) &mem_buffer[n][mem_idx_n];
+    mem_idx[n] += len;
+    mem->next = mh->next;
+    mh->next = mem;
+    return mem->ptr = (void *) &mem[1];
+}
+
+void free_mem(struct memh *mh) {
+    int n = MEM_HEADER_TO_N(mh);
+    mem_idx[n] = 0;
+#if MEM_DEBUG
+    printf("free_mem: n is %d\n", n);
+#endif
+}
+
+#endif
+
+/* creates an empty variable table */
+struct vartable *create_vartable() {
+    struct memh *mh = create_mem();
+    struct vartable *vt;
+    if(!mh) {
+            return NULL;
+    }
+    vt = (struct vartable *) mem_alloc(mh, sizeof(struct vartable));
+    if (mh && vt) vt->mh = mh, vt->first = NULL; else free_mem(mh);
+    return vt;
+}
+
+/* frees a variable table */
+void free_vartable(struct vartable *vt) {
+    free_mem(vt->mh);
+}
+
+/* gets a variable out of a variable table */
+struct var *get_var(struct vartable *vt, char *name) {
+    struct var *v;
+    if (!vt || !name) return NULL;
+    for (v = vt->first; v; v = v->next) if (same_str(v->name, name)) return v;
+    return NULL;
+}
+
+/* creates a new variable in a variable table */
+struct var *put_var(struct vartable *vt, char *name, struct val *value) {
+    struct var *v;
+    char *n;
+
+    if (!vt || !name || !value) return NULL;
+
+    if ((v = get_var(vt, name))) {
+        v->val = *value;
+        return v;
+    }
+
+    v = (struct var *) mem_alloc(vt->mh, sizeof(struct var));
+    n = (char *) mem_alloc(vt->mh, strlen(name)+1);
+    if (v && n) {
+        strcpy(n, name);
+        v->name = n;
+        v->val  = *value;
+        v->next = vt->first;
+        vt->first = v;
+        return v;
+    }
+    return NULL;
+}
diff --git a/minix/llvm/static/magic/magic_mem.c b/minix/llvm/static/magic/magic_mem.c
new file mode 100644 (file)
index 0000000..77b2eb2
--- /dev/null
@@ -0,0 +1,2108 @@
+
+#ifdef _FILE_OFFSET_BITS
+#undef _FILE_OFFSET_BITS
+#endif
+#define _FILE_OFFSET_BITS 64
+
+#include <magic_mem.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <magic_asr.h>
+
+#ifdef __MINIX
+#define util_time_tsc_read_ns(x) 0
+#define util_strhash(x, y) 0
+#define util_stacktrace_hash() 0
+#define util_stacktrace_print_custom(x)
+#define util_stacktrace_hash_skip(x) 0
+#else
+#include <common/util/stacktrace.h>
+#include <common/util/time.h>
+#include <common/util/string.h>
+#endif
+
+#define DEBUG                           MAGIC_DEBUG_SET(0)
+#define DEBUG_TYPE_SIZE_MISMATCH        MAGIC_DEBUG_SET(0)
+
+#if DEBUG
+#define MAGIC_MEM_PRINTF _magic_printf
+#else
+#define MAGIC_MEM_PRINTF magic_null_printf
+#endif
+
+/* CPU frequency (used for timestamp logging) */
+PUBLIC double magic_cycles_per_ns = 0;
+
+/*
+ * External callbacks.
+ */
+PUBLIC magic_mem_heap_alloc_cb_t magic_mem_heap_alloc_cb = NULL;
+PUBLIC magic_mem_create_dsentry_cb_t magic_mem_create_dsentry_cb = NULL;
+PUBLIC magic_mem_heap_free_cb_t magic_mem_heap_free_cb = NULL;
+
+PUBLIC short magic_mem_create_dsentry_site_id = 0;
+PUBLIC THREAD_LOCAL short magic_mem_wrapper_active = 0;
+PUBLIC THREAD_LOCAL short magic_mempool_mgmt_active_level = 0;
+PUBLIC THREAD_LOCAL short magic_mempool_ids[MAGIC_MEMPOOL_MAX_FUNC_RECURSIONS];
+
+char* const MAGIC_MEMPOOL_NAME_UNKNOWN = "_magic_mempool_unknown#";
+char* const MAGIC_MEMPOOL_NAME_DETACHED = "_magic_mempool_detached#";
+
+__attribute__((weak)) int magic_mempool_allow_reset = 1;
+__attribute__((weak)) int magic_mempool_allow_reuse = 1;
+__attribute__((weak)) int magic_mempool_allow_external_alloc = 0;
+
+#define MAGIC_MEM_FAILED    ((void*) -1)
+
+#ifndef SHM_REMAP
+#define SHM_REMAP 0
+#endif
+
+EXTERN char **environ;
+
+PRIVATE magic_dsentry_cb_t magic_destroy_dsentry_ext_cb = NULL;
+
+/* Magic real mem function definitions. */
+PUBLIC void *(*magic_real_malloc)(size_t size) = &malloc;
+PUBLIC void *(*magic_real_calloc)(size_t nmemb, size_t size) = &calloc;
+PUBLIC void  (*magic_real_free)(void *ptr) = &free;
+PUBLIC void *(*magic_real_realloc)(void *ptr, size_t size) = &realloc;
+
+PUBLIC int (*magic_real_posix_memalign)(void **memptr, size_t alignment, size_t size) = &posix_memalign;
+
+#ifndef __MINIX
+PUBLIC void *(*magic_real_valloc)(size_t size) = &valloc;
+PUBLIC void *(*magic_real_memalign)(size_t boundary, size_t size) = &memalign;
+#endif
+
+PUBLIC void *(*magic_real_mmap)(void *start, size_t length, int prot, int flags,
+    int fd, off_t offset) = &mmap;
+PUBLIC int (*magic_real_munmap)(void *start, size_t length) = &munmap;
+
+PUBLIC int (*magic_real_brk)(void *addr) = &brk;
+PUBLIC void *(*magic_real_sbrk)(intptr_t increment) = &sbrk;
+
+#ifndef __MINIX
+PUBLIC void *(*magic_real_shmat)(int shmid, const void *shmaddr, int shmflg) = &shmat;
+PUBLIC int (*magic_real_shmdt)(const void *shmaddr) = &shmdt;
+
+PUBLIC void *(*magic_real_mmap64)(void *start, size_t length, int prot, int flags,
+    int fd, off_t pgoffset) = &mmap64;
+#else
+PUBLIC void *(*magic_real_vm_map_cacheblock)(dev_t dev, off_t dev_offset,
+    ino_t ino, off_t ino_offset, u32_t *flags, int blocksize) = &vm_map_cacheblock;
+#endif
+
+/* Use magic_real* functions in the rest of the file. */
+#include <magic_real_mem.h>
+
+/* Macros for memory usage logging. */
+#if MAGIC_MEM_USAGE_OUTPUT_CTL
+#define MAGIC_MEM_DEBUG_PREFIX "MEM_USAGE: "
+#define TIMESTAMP_STR "%llu"
+#define TIMESTAMP_ARG (util_time_tsc_read_ns(magic_cycles_per_ns))
+#define MAGIC_MEM_DEBUG_EVENT(EVENT, FORMAT, ...) \
+       _magic_printf(MAGIC_MEM_DEBUG_PREFIX TIMESTAMP_STR " " #EVENT " " FORMAT "\n", TIMESTAMP_ARG, __VA_ARGS__)
+#define MAGIC_MEM_DEBUG_EVENT_1(event, ptr)                 MAGIC_MEM_DEBUG_EVENT(event, "%u", (unsigned) ptr)
+#define MAGIC_MEM_DEBUG_EVENT_2(event, ptr, type)           MAGIC_MEM_DEBUG_EVENT(event, "%u %lu", (unsigned) ptr, type)
+#define MAGIC_MEM_DEBUG_EVENT_3(event, ptr, type, size)     MAGIC_MEM_DEBUG_EVENT(event, "%u %lu %d", (unsigned) ptr, type, size)
+
+#if (MAGIC_MEM_USAGE_OUTPUT_CTL == 1)
+/* use the hash of the name (extended with line number & file name) as dynamic type */
+#define        MAGIC_MEM_GET_DTYPE() util_strhash(0, name)
+#elif (MAGIC_MEM_USAGE_OUTPUT_CTL == 2)
+/* use the hash of the stacktrace as a dynamic type */
+#define        MAGIC_MEM_GET_DTYPE() util_stacktrace_hash()
+#endif
+#define MAGIC_MEM_DEBUG_ALLOC(ptr, size)            MAGIC_MEM_DEBUG_EVENT_3(alloc, ptr, (MAGIC_MEMPOOL_MGMT_IS_ACTIVE() ? MAGIC_MEMPOOL_GET_DTYPE() : MAGIC_MEM_GET_DTYPE()), size)
+#define MAGIC_MEM_DEBUG_FREE(ptr)                   MAGIC_MEM_DEBUG_EVENT_1(dealloc, ptr)
+#define MAGIC_MEM_DEBUG_RESET(ptr)                  MAGIC_MEM_DEBUG_EVENT_1(reset, ptr)
+#define MAGIC_MEM_DEBUG_REUSE(ptr, type)            MAGIC_MEM_DEBUG_EVENT_2(reuse, ptr, type)
+#else
+#define MAGIC_MEM_GET_DTYPE() 0
+#define MAGIC_MEM_DEBUG_ALLOC(ptr, size)
+#define MAGIC_MEM_DEBUG_FREE(ptr)
+#define MAGIC_MEM_DEBUG_RESET(ptr)
+#define MAGIC_MEM_DEBUG_REUSE(ptr, type)
+#endif
+
+/*===========================================================================*
+ *                       magic_mempool_alloc_id                              *
+ *===========================================================================*/
+MAGIC_MACRO_FUNC short magic_mempool_alloc_id()
+{
+    short i, id = -1;
+
+    MAGIC_MPDESC_LOCK();
+
+    /* Find a free slot. */
+    for(i = 0; i < MAGIC_MAX_MEMPOOLS; i++) {
+        if(MAGIC_MPDESC_IS_FREE(&_magic_mpdescs[i])) {
+            MAGIC_MPDESC_ALLOC(&_magic_mpdescs[i]);
+            id = i + 1;
+            break;
+        }
+    }
+
+    MAGIC_MPDESC_UNLOCK();
+
+    assert((id > 0) && (id <= MAGIC_MAX_MEMPOOLS) && "Ran out of memory pool descriptors!");
+
+    return id;
+}
+
+/*===========================================================================*
+ *                       magic_mempool_create_begin                          *
+ *===========================================================================*/
+MAGIC_HOOK void magic_mempool_create_begin(__MDEBUG_ARGS__)
+{
+    MAGIC_MEMPOOL_MGMT_SET_ACTIVE();
+    assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
+    MAGIC_MEMPOOL_SET_ID(magic_mempool_alloc_id());
+    MAGIC_MEMPOOL_SET_DTYPE(MAGIC_MEM_GET_DTYPE());
+}
+
+/*===========================================================================*
+ *                       magic_mempool_create_end                            *
+ *===========================================================================*/
+MAGIC_HOOK void magic_mempool_create_end(void* addr, int indirection)
+{
+    void* pool;
+    pool = (indirection && addr) ? *((void**)addr) : addr;
+    assert(pool && "Cannot have a NULL pool pointer.");
+    _magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1].addr = pool;
+    magic_mempool_mgmt_end();
+}
+
+/*===========================================================================*
+ *                       magic_mempool_lookup_by_addr                        *
+ *===========================================================================*/
+MAGIC_MACRO_FUNC short magic_mempool_lookup_by_addr(void* addr)
+{
+    short i, id = MAGIC_MEMPOOL_ID_UNKNOWN;
+
+    if (addr) {
+        for(i = 0; i < MAGIC_MAX_MEMPOOLS; i++) {
+            if(_magic_mpdescs[i].addr == addr) {
+                id = i + 1;
+                break;
+            }
+        }
+    }
+
+    return id;
+}
+
+/*===========================================================================*
+ *                       magic_mempool_reset                                 *
+ *===========================================================================*/
+MAGIC_MACRO_FUNC void magic_mempool_reset(char* mempool_name, int reset_name)
+{
+    struct _magic_dsentry *prev_dsentry, *dsentry, *block_dsentry;
+    struct _magic_sentry* sentry;
+
+    MAGIC_DSENTRY_LOCK();
+    MAGIC_DSENTRY_MEMPOOL_ALIVE_ITER(_magic_first_mempool_dsentry, prev_dsentry, dsentry, sentry,
+        if (sentry->name == mempool_name) {
+            block_dsentry = MAGIC_DSENTRY_NEXT_MEMBLOCK(dsentry);
+            if (block_dsentry != NULL) {
+                struct _magic_dsentry *tmp_block_dsentry = MAGIC_CAS(&MAGIC_DSENTRY_NEXT_MEMBLOCK(dsentry), block_dsentry, NULL);
+                assert(tmp_block_dsentry == block_dsentry && "New blocks have been allocated from a reseted mempool!");
+            }
+            if (reset_name) {
+                char *tmp_name = MAGIC_CAS(&sentry->name, mempool_name, MAGIC_MEMPOOL_NAME_UNKNOWN);
+                assert(tmp_name == mempool_name && "The name of the mempool has changed while being reseted!");
+            }
+            MAGIC_MEM_DEBUG_RESET((char*)dsentry);
+        }
+    );
+
+    MAGIC_DSENTRY_UNLOCK();
+}
+
+/*===========================================================================*
+ *                       magic_mempool_destroy_begin                         *
+ *===========================================================================*/
+MAGIC_HOOK void magic_mempool_destroy_begin(void* addr, int memory_reuse)
+{
+    magic_mempool_mgmt_begin(addr);
+    if (addr && memory_reuse) {
+        assert(MAGIC_MEMPOOL_ID_IS_SET() && "Cannot destroy a pool with an unknown id.");
+        magic_mempool_reset(MAGIC_MEMPOOL_GET_NAME(), TRUE);
+    }
+}
+
+/*===========================================================================*
+ *                       magic_mempool_destroy_end                           *
+ *===========================================================================*/
+MAGIC_HOOK void magic_mempool_destroy_end()
+{
+    MAGIC_MPDESC_LOCK();
+
+    MAGIC_MPDESC_FREE(&_magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1]);
+
+    MAGIC_MPDESC_UNLOCK();
+
+    magic_mempool_mgmt_end();
+}
+
+/*===========================================================================*
+ *                       magic_mempool_mgmt_begin                            *
+ *===========================================================================*/
+MAGIC_HOOK void  magic_mempool_mgmt_begin(void* addr)
+{
+    short id;
+
+    MAGIC_MEMPOOL_MGMT_SET_ACTIVE();
+    assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
+
+    id = magic_mempool_lookup_by_addr(addr);
+    /* For some reason, this mempool has not been registered yet, reserve a new slot in the mempool array. */
+    if (addr && (id == MAGIC_MEMPOOL_ID_UNKNOWN)) {
+        id = magic_mempool_alloc_id();
+        _magic_mpdescs[id - 1].addr = addr;
+    }
+    MAGIC_MEMPOOL_SET_ID(id);
+}
+
+/*===========================================================================*
+ *                       magic_mempool_mgmt_end                              *
+ *===========================================================================*/
+MAGIC_HOOK void magic_mempool_mgmt_end()
+{
+    MAGIC_MEMPOOL_SET_ID(MAGIC_MEMPOOL_ID_UNKNOWN);
+    assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
+    MAGIC_MEMPOOL_MGMT_UNSET_ACTIVE();
+}
+
+/*===========================================================================*
+ *                       magic_mempool_reset_begin                           *
+ *===========================================================================*/
+MAGIC_HOOK void magic_mempool_reset_begin(void* addr)
+{
+    magic_mempool_mgmt_begin(addr);
+    /* skip reset when it has been disabled by the application. */
+    if (magic_mempool_allow_reset) {
+        if (addr != NULL) {
+            assert(MAGIC_MEMPOOL_ID_IS_SET() && "Cannot reset a pool with an unknown id.");
+            magic_mempool_reset(MAGIC_MEMPOOL_GET_NAME(), TRUE);
+        }
+    }
+}
+
+/*===========================================================================*
+ *                       magic_mempool_dsentry_set_name                      *
+ *===========================================================================*/
+MAGIC_MACRO_FUNC void magic_mempool_dsentry_set_name(struct _magic_dsentry* dsentry, char* name)
+{
+    char *old_name, *ret;
+
+    if ((name == MAGIC_MEMPOOL_NAME_UNKNOWN) || (name == MAGIC_MEMPOOL_NAME_DETACHED)) {
+        do {
+            old_name = MAGIC_DSENTRY_TO_SENTRY(dsentry)->name;
+        } while (MAGIC_CAS(&MAGIC_DSENTRY_TO_SENTRY(dsentry)->name, old_name, name) != old_name && old_name != name);
+    } else {
+        old_name = MAGIC_DSENTRY_TO_SENTRY(dsentry)->name;
+        if (old_name != name) {
+            if (!strncmp(old_name, MAGIC_MEMPOOL_NAME_PREFIX, strlen(MAGIC_MEMPOOL_NAME_PREFIX))) {
+                assert(((old_name == MAGIC_MEMPOOL_NAME_UNKNOWN) || (old_name == MAGIC_MEMPOOL_NAME_DETACHED))
+                        && "Cannot overwrite an already existing valid memory pool name!");
+            }
+            ret = MAGIC_CAS(&MAGIC_DSENTRY_TO_SENTRY(dsentry)->name, old_name, name);
+            assert((ret == old_name || ret == name) && "Cannot overwrite an already existing valid memory pool name!");
+        }
+    }
+}
+
+/*===========================================================================*
+ *                       magic_mempool_dsentry_update                        *
+ *===========================================================================*/
+MAGIC_MACRO_FUNC void magic_mempool_dsentry_update(struct _magic_dsentry* dsentry, char* name)
+{
+    struct _magic_sentry* sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+    struct _magic_dsentry* next_mempool_dsentry;
+    int flags;
+    /* set the magic state mempool flag atomically */
+    do {
+        flags = sentry->flags;
+    } while (MAGIC_CAS(&sentry->flags, flags, flags | MAGIC_STATE_MEMPOOL) != flags && !(flags & MAGIC_STATE_MEMPOOL));
+    magic_mempool_dsentry_set_name(dsentry, name);
+    /* the thread that updates the id adds the dsentry to the mempool dsentry list */
+    if (!(flags & MAGIC_STATE_MEMPOOL)) {
+        /* Add the new dsentry before the first dsentry atomically. */
+        do {
+            next_mempool_dsentry = _magic_first_mempool_dsentry;
+            MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) = next_mempool_dsentry;
+        } while(MAGIC_CAS(&_magic_first_mempool_dsentry, next_mempool_dsentry, dsentry) != next_mempool_dsentry);
+    }
+}
+
+/*===========================================================================*
+ *                       mempool_block_alloc_template                        *
+ *===========================================================================*/
+MAGIC_FUNC void *mempool_block_alloc_template(void* addr, size_t size)
+{
+    return NULL;
+}
+
+/*===========================================================================*
+ *                       magic_mempool_block_alloc_template                  *
+ *===========================================================================*/
+PUBLIC void *magic_mempool_block_alloc_template(__MA_ARGS__ void* addr, size_t size)
+{
+    void *ptr, *data_ptr;
+    struct _magic_sentry* mempool_sentry;
+    struct _magic_dsentry* mempool_dsentry, *next_block_dsentry;
+
+    magic_mempool_mgmt_begin(addr);
+    /* don't set the memory wrapper flag, this function is supposed to allocate memory from a pool
+     and not using the standard allocators. it might also call other memory pool management functions */
+    if(size > 0) {
+        /* this call should be replaced with a call to a "real" block allocation function, when generating custom wrappers */
+        ptr = mempool_block_alloc_template(addr, MAGIC_SIZE_TO_REAL(size) + magic_asr_get_padding_size(MAGIC_STATE_HEAP));
+        MAGIC_MEM_PRINTF("%s: ptr = malloc(size) <-> 0x%08x = malloc(%d)\n", __FUNCTION__,(unsigned) ptr, MAGIC_SIZE_TO_REAL(size));
+        data_ptr = magic_alloc(__MA_VALUES__ ptr, size, MAGIC_STATE_HEAP | MAGIC_STATE_MEMBLOCK);
+        if(data_ptr == MAGIC_MEM_FAILED) {
+            /* cannot free individual blocks inside the pool */
+            data_ptr = NULL;
+            errno = ENOMEM;
+        } else if (ptr) {
+            /* lookup the pool buffer dsentry from which this block was allocated */
+            mempool_sentry = magic_mempool_sentry_lookup_by_range(ptr, NULL);
+            if (!mempool_sentry && magic_mempool_allow_external_alloc) {
+                mempool_sentry = magic_sentry_lookup_by_range(ptr, NULL);
+                if (mempool_sentry) {
+                    magic_mempool_dsentry_update(MAGIC_DSENTRY_FROM_SENTRY(mempool_sentry), MAGIC_MEMPOOL_GET_NAME());
+                }
+            }
+
+            assert(mempool_sentry && "XXX Mempool dsentry not found for this memblock dsentry: memory not allocated from a memory pool management function?");
+            mempool_dsentry = MAGIC_DSENTRY_FROM_SENTRY(mempool_sentry);
+
+            /* Reuse of buffers across pools - propagate the new pool name */
+            if (MAGIC_MEMPOOL_ID_IS_SET() && (mempool_sentry->name != MAGIC_MEMPOOL_GET_NAME())) {
+                assert(magic_mempool_allow_reuse && "Pool memory reuse is disabled!");
+                magic_mempool_dsentry_set_name(mempool_dsentry, MAGIC_MEMPOOL_GET_NAME());
+            }
+            MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr)))->name = mempool_sentry->name;
+
+            /* Add the new dsentry before the first block dsentry chained to the memory pool dsentry, atomically.
+             The list should be circular - the last block dsentry (first one added) points to the memory pool dsentry. */
+            do {
+                next_block_dsentry = MAGIC_DSENTRY_NEXT_MEMBLOCK(mempool_dsentry);
+                MAGIC_DSENTRY_NEXT_MEMBLOCK(MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))) = next_block_dsentry ? next_block_dsentry : mempool_dsentry;
+            }while(MAGIC_CAS(&(MAGIC_DSENTRY_NEXT_MEMBLOCK(mempool_dsentry)), next_block_dsentry, MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))) != next_block_dsentry);
+
+            /* First write to this pool buffer, potential reuse */
+            if (next_block_dsentry == NULL) {
+               MAGIC_MEM_DEBUG_REUSE((char*)mempool_dsentry, MAGIC_MEMPOOL_GET_DTYPE());
+            }
+        }
+    }
+    else {
+        /* Some applications return a valid pointer even if size is 0... */
+        data_ptr = mempool_block_alloc_template(addr, size);
+    }
+    magic_mempool_mgmt_end();
+
+    return data_ptr;
+}
+
+/*===========================================================================*
+ *                       magic_create_dsentry                                *
+ *===========================================================================*/
+PUBLIC int magic_create_dsentry(struct _magic_dsentry *dsentry,
+    void *data_ptr, struct _magic_type *type, size_t size, int flags,
+    char *name, char *parent_name)
+{
+    /* This function does not require any dsentry locking. */
+    struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+    struct _magic_dsentry *next_dsentry, *next_mempool_dsentry;
+    size_t type_size;
+    int is_varsized = 0;
+    int num_vsa_elements = 0;
+
+    struct _magic_dsentry *saved_next = dsentry->next;
+    int save_linkage = ((flags & MAGIC_STATE_HEAP) && _magic_vars->fake_malloc);
+
+    MAGIC_MEM_PRINTF("Dsentry created from stacktrace:\n");
+    if (MAGIC_MEM_PRINTF != magic_null_printf) {
+        MAGIC_MEM_WRAPPER_BEGIN();
+        util_stacktrace_print_custom(MAGIC_MEM_PRINTF);
+        MAGIC_MEM_WRAPPER_END();
+    }
+
+    if (!type) {
+        type = MAGIC_VOID_TYPE;
+    }
+    type_size = type->size;
+    assert(size > 0);
+
+    memcpy(dsentry, &magic_default_dsentry, sizeof(struct _magic_dsentry));
+
+    /* Catch variable-sized struct allocation. */
+    if (magic_type_alloc_needs_varsized_array(type, size, &num_vsa_elements)) {
+        is_varsized = 1;
+    }
+
+    if (size % type_size != 0 && !is_varsized) {
+        /* This should only happen for uncaught variable-sized struct allocations. */
+#if DEBUG_TYPE_SIZE_MISMATCH
+        _magic_printf("magic_create_dsentry: type <-> size mismatch, reverting to void type: size=%d, type=", size);
+        MAGIC_TYPE_PRINT(type, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+#endif
+        type = MAGIC_VOID_TYPE;
+        type_size = type->size;
+        flags |= MAGIC_STATE_TYPE_SIZE_MISMATCH;
+    }
+
+    if (size == type_size && !is_varsized) {
+        sentry->type = type;
+    }
+    else {
+        struct _magic_type *array_type = &(dsentry->type);
+        MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(array_type, type,
+            MAGIC_DSENTRY_TO_TYPE_ARR(dsentry), size, num_vsa_elements);
+        array_type->id = MAGIC_FAA(&_magic_types_next_id, 1);
+        assert(_magic_types_next_id < MAGIC_ID_MAX);
+        sentry->type = array_type;
+    }
+
+    sentry->flags |= flags;
+    sentry->address = data_ptr;
+
+    if (name) {
+        sentry->name = name;
+    }
+    if (parent_name) {
+        dsentry->parent_name = parent_name;
+    }
+    sentry->id = MAGIC_FAA(&_magic_sentries_next_id, 1);
+    assert(_magic_sentries_next_id < MAGIC_ID_MAX);
+
+    /*
+     * TODO: Also add per-callsite index to handle the following:
+     * for (;;) { p = malloc(); }
+     */
+    if (magic_mem_create_dsentry_site_id) {
+        MAGIC_MEM_WRAPPER_BEGIN();
+        /*
+         * XXX: This is so damn ugly, but we don't want to include
+         * any magic_* functions in the stacktrace hash.
+         * This should probably be done in a much more elegant manner.
+         */
+        dsentry->site_id = util_stacktrace_hash_skip((char *)"("MAGIC_PREFIX_STR);
+        MAGIC_MEM_WRAPPER_END();
+    }
+
+    if (save_linkage) {
+        dsentry->next = saved_next;
+        return 0;
+    }
+
+    /* Add the new dsentry before the first dsentry atomically.
+     * Skip memblock dsentries to make pool reset/destruction faster.
+     */
+    if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_MEMBLOCK)) {
+        do {
+            next_dsentry = _magic_first_dsentry;
+            MAGIC_DSENTRY_NEXT(dsentry) = next_dsentry;
+        } while(MAGIC_CAS(&_magic_first_dsentry, next_dsentry, dsentry) != next_dsentry);
+    }
+
+#if MAGIC_DSENTRY_ALLOW_PREV
+    next_dsentry = MAGIC_DSENTRY_NEXT(dsentry);
+    if (next_dsentry) {
+        MAGIC_DSENTRY_PREV(next_dsentry) = dsentry;
+    }
+    MAGIC_DSENTRY_PREV(dsentry) = NULL;
+#endif
+
+    if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_MEMPOOL)) {
+        /* Add the new dsentry before the first mempool dsentry atomically. */
+        do {
+            next_mempool_dsentry = _magic_first_mempool_dsentry;
+            MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) = next_mempool_dsentry;
+        } while(MAGIC_CAS(&_magic_first_mempool_dsentry, next_mempool_dsentry, dsentry) != next_mempool_dsentry);
+    }
+    magic_update_dsentry_ranges = 1;
+
+    if (magic_mem_create_dsentry_cb)
+        magic_mem_create_dsentry_cb(dsentry);
+
+    return 0;
+}
+
+/*===========================================================================*
+ *                      magic_create_obdsentry                               *
+ *===========================================================================*/
+PUBLIC struct _magic_obdsentry* magic_create_obdsentry(void *data_ptr,
+    struct _magic_type *type, size_t size, int flags,
+    char *name, char *parent_name)
+{
+    struct _magic_obdsentry *obdsentry = NULL;
+    int i, ret;
+
+    /* Check name. */
+    if(!name || !strcmp(name, "")) {
+        return NULL;
+    }
+    else if(strlen(name) >= MAGIC_MAX_OBDSENTRY_NAME_LEN) {
+        return NULL;
+    }
+
+    /* Check parent name. */
+    if(!parent_name || !strcmp(parent_name, "")) {
+        parent_name = MAGIC_OBDSENTRY_DEFAULT_PARENT_NAME;
+    }
+    if(strlen(parent_name) >= MAGIC_MAX_OBDSENTRY_PARENT_NAME_LEN) {
+        return NULL;
+    }
+
+    MAGIC_MEM_WRAPPER_LBEGIN();
+
+    /* Find a free slot. */
+    for(i=0;i<MAGIC_MAX_OBDSENTRIES;i++) {
+        if(MAGIC_OBDSENTRY_IS_FREE(&_magic_obdsentries[i])) {
+            obdsentry = &_magic_obdsentries[i];
+            break;
+        }
+    }
+    if(!obdsentry) {
+        MAGIC_MEM_WRAPPER_LEND();
+        return NULL;
+    }
+
+    /* Create the dsentry. */
+    strcpy(obdsentry->name, name);
+    strcpy(obdsentry->parent_name, parent_name);
+    flags |= MAGIC_STATE_OUT_OF_BAND;
+    ret = magic_create_dsentry(MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry), data_ptr, type,
+        size, flags, obdsentry->name, obdsentry->parent_name);
+
+    MAGIC_MEM_WRAPPER_LEND();
+
+    if(ret < 0) {
+        return NULL;
+    }
+    assert(!MAGIC_OBDSENTRY_IS_FREE(obdsentry));
+
+    return obdsentry;
+}
+
+/*===========================================================================*
+ *                       magic_update_dsentry_state                          *
+ *===========================================================================*/
+PUBLIC int magic_update_dsentry_state(struct _magic_dsentry *dsentry,
+    unsigned long state)
+{
+    int ret = 0;
+    unsigned long old_state;
+    unsigned long num_dead_dsentries;
+    unsigned long size, size_dead_dsentries;
+    size = MAGIC_DSENTRY_TO_SENTRY(dsentry)->type->size;
+
+    switch(state) {
+        case MAGIC_DSENTRY_MSTATE_FREED:
+            old_state = MAGIC_CAS(&dsentry->magic_state, MAGIC_DSENTRY_MSTATE_DEAD,
+                MAGIC_DSENTRY_MSTATE_FREED);
+            if(old_state != MAGIC_DSENTRY_MSTATE_DEAD) {
+                ret = MAGIC_EBADMSTATE;
+                break;
+            }
+            if (!MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(dsentry), MAGIC_STATE_MEMBLOCK)) {
+                num_dead_dsentries = MAGIC_FAS(&magic_num_dead_dsentries, 1) - 1;
+                size_dead_dsentries = MAGIC_FAS(&magic_size_dead_dsentries, size) - size;
+                MAGIC_MEM_PRINTF("magic_update_dsentry_state:  --magic_num_dead_dsentries (num=%d, size=%d)\n", num_dead_dsentries, size_dead_dsentries);
+            }
+        break;
+        case MAGIC_DSENTRY_MSTATE_DEAD:
+            old_state = MAGIC_CAS(&dsentry->magic_state, MAGIC_DSENTRY_MSTATE_ALIVE,
+                MAGIC_DSENTRY_MSTATE_DEAD);
+            if(old_state != MAGIC_DSENTRY_MSTATE_ALIVE) {
+                ret = (old_state == MAGIC_DSENTRY_MSTATE_DEAD
+                    || old_state == MAGIC_DSENTRY_MSTATE_FREED)
+                    ? MAGIC_EBADMSTATE : MAGIC_EBADENT;
+                break;
+            }
+            MAGIC_DSENTRY_TO_SENTRY(dsentry)->id = MAGIC_FAA(&_magic_sentries_next_id, 1);
+            assert(_magic_sentries_next_id < MAGIC_ID_MAX);
+            if (!MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(dsentry), MAGIC_STATE_MEMBLOCK)) {
+                num_dead_dsentries = MAGIC_FAA(&magic_num_dead_dsentries, 1) + 1;
+                size_dead_dsentries = MAGIC_FAA(&magic_size_dead_dsentries, size) + size;
+                MAGIC_MEM_PRINTF("magic_update_dsentry_state:  ++magic_num_dead_dsentries (num=%d, size=%d)\n", num_dead_dsentries, size_dead_dsentries);
+                if(!magic_ignore_dead_dsentries
+                    && MAGIC_DEAD_DSENTRIES_NEED_FREEING()) {
+                    magic_free_dead_dsentries();
+                }
+            }
+        break;
+        default:
+            ret = MAGIC_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                            magic_free_dsentry                             *
+ *===========================================================================*/
+PRIVATE int magic_free_dsentry(struct _magic_dsentry *dsentry)
+{
+    int ret = 0;
+    struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+    int region = MAGIC_STATE_REGION(sentry);
+    void *ptr = MAGIC_PTR_FROM_DSENTRY(dsentry);
+    size_t page_size, size;
+    void *data_ptr, *aligned_ptr;
+    int from_wrapper = MAGIC_MEM_WRAPPER_IS_ACTIVE();
+    assert(dsentry->magic_number == MAGIC_DSENTRY_MNUM_NULL);
+
+    if (!from_wrapper) {
+        MAGIC_MEM_WRAPPER_BEGIN();
+    }
+
+    if (magic_mem_heap_free_cb) {
+        ret = magic_mem_heap_free_cb(dsentry);
+        if (ret != MAGIC_ENOENT)
+            return ret;
+
+        /*
+         * If the callback returned MAGIC_ENOENT, fallback to
+         * the default behavior.
+         */
+        ret = 0;
+    }
+
+    /* A MAP_SHARED region will have both MAGIC_STATE_MAP and MAGIC_STATE_SHM. */
+    if (region == (MAGIC_STATE_MAP | MAGIC_STATE_SHM))
+        region = MAGIC_STATE_MAP;
+    switch (region) {
+        case MAGIC_STATE_HEAP:
+            MAGIC_MEM_DEBUG_FREE(ptr);
+            free(ptr);
+        break;
+        case MAGIC_STATE_MAP:
+        case MAGIC_STATE_SHM:
+            page_size = MAGIC_PAGE_SIZE;
+            size = MAGIC_DSENTRY_TO_SENTRY(dsentry)->type->size;
+            data_ptr = MAGIC_PTR_TO_DATA(ptr);
+            aligned_ptr = ((char *)data_ptr) - page_size;
+
+            if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_DETACHED)) {
+                size_t padding_size = (size_t) dsentry->ext;
+                MAGIC_MEM_DEBUG_FREE(ptr);
+                ret = munmap(((char *)aligned_ptr) - padding_size, page_size + size + padding_size);
+            }
+            else {
+#ifndef __MINIX
+                if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_SHM))
+                    ret = shmdt(data_ptr);
+                else
+#endif
+                    ret = munmap(data_ptr, size);
+                MAGIC_MEM_DEBUG_FREE(ptr);
+                munmap(aligned_ptr, page_size);
+            }
+            if (ret != 0) {
+                ret = MAGIC_EBADENT;
+            }
+        break;
+        default:
+            ret = MAGIC_EBADENT;
+        break;
+    }
+    if (!from_wrapper) {
+        MAGIC_MEM_WRAPPER_END();
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                    magic_free_dead_dsentries                              *
+ *===========================================================================*/
+PUBLIC void magic_free_dead_dsentries()
+{
+    struct _magic_dsentry *prev_dsentry, *dsentry, *next_first_dsentry, *skipped_dsentry;
+    struct _magic_sentry *sentry;
+    unsigned long num_dead_dsentries;
+    int dead_dsentries_left;
+    int ret;
+
+    MAGIC_DSENTRY_LOCK();
+
+    skipped_dsentry = NULL;
+    num_dead_dsentries = magic_num_dead_dsentries;
+    next_first_dsentry = _magic_first_dsentry;
+    if (next_first_dsentry) {
+        /* if the first dsentry is dead, skip it to eliminate contention on the list head */
+        if (next_first_dsentry->magic_state == MAGIC_DSENTRY_MSTATE_DEAD){
+            num_dead_dsentries--;
+        }
+    }
+
+    if(!next_first_dsentry || num_dead_dsentries == 0) {
+        MAGIC_DSENTRY_UNLOCK();
+        return;
+    }
+
+    MAGIC_MEM_PRINTF("magic_free_dead_dsentries: Freeing %d dead dsentries...\n", num_dead_dsentries);
+
+    /* Eliminate the dead dsentries but always skip the first one to eliminate contention on the head. */
+    do {
+        dead_dsentries_left = 0;
+        MAGIC_DSENTRY_ITER(next_first_dsentry->next, prev_dsentry, dsentry, sentry,
+            /* normal dsentry to be freed */
+            if ((dsentry->magic_state != MAGIC_DSENTRY_MSTATE_DEAD) ||
+                    (magic_update_dsentry_state(dsentry, MAGIC_DSENTRY_MSTATE_FREED) < 0)) {
+                next_first_dsentry = dsentry;
+            } else {
+                magic_destroy_dsentry(dsentry, prev_dsentry);
+                ret = magic_free_dsentry(dsentry);
+                if(ret != 0) {
+                    _magic_printf("Warning: magic_free_dsentry failed with return code %d for: ", ret);
+                    MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
+                    MAGIC_MEM_PRINTF("\n");
+                }
+                num_dead_dsentries--;
+                dead_dsentries_left = 1;
+                break;
+            }
+        );
+    } while(dead_dsentries_left && num_dead_dsentries > 0);
+    assert(num_dead_dsentries == 0);
+
+    MAGIC_DSENTRY_UNLOCK();
+}
+
+/*===========================================================================*
+ *                      magic_destroy_dsentry                                *
+ *===========================================================================*/
+PUBLIC void magic_destroy_dsentry(struct _magic_dsentry *dsentry,
+    struct _magic_dsentry *prev_dsentry)
+{
+    struct _magic_dsentry *next_dsentry, *next_mempool_dsentry, *prev_mempool_dsentry = NULL;
+    int dsentry_destroyed, mempool_dsentry_destroyed;
+
+    if(magic_destroy_dsentry_ext_cb && MAGIC_DSENTRY_HAS_EXT(dsentry)) {
+        magic_destroy_dsentry_ext_cb(dsentry);
+    }
+    if (MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(dsentry), MAGIC_STATE_MEMPOOL)) {
+        do {
+            if(!prev_mempool_dsentry) {
+                if(MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) != MAGIC_DSENTRY_NEXT_MEMPOOL(_magic_first_mempool_dsentry)) {
+                    prev_mempool_dsentry = magic_mempool_dsentry_prev_lookup(dsentry);
+                    assert(prev_mempool_dsentry != (struct _magic_dsentry *) MAGIC_ENOPTR && "Dsentry not found!");
+                }
+            }
+            if(prev_mempool_dsentry) {
+                MAGIC_DSENTRY_NEXT_MEMPOOL(prev_mempool_dsentry) = MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry);
+                mempool_dsentry_destroyed = 1;
+            }
+            else {
+                /* Remove the first dsentry atomically. */
+                next_mempool_dsentry = MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry);
+                mempool_dsentry_destroyed = (MAGIC_CAS(&_magic_first_mempool_dsentry,
+                    dsentry, next_mempool_dsentry) == dsentry);
+            }
+        } while(!mempool_dsentry_destroyed);
+        MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) = NULL;
+    }
+    do {
+#if MAGIC_DSENTRY_ALLOW_PREV
+        prev_dsentry = MAGIC_DSENTRY_PREV(dsentry);
+#else
+        if(!prev_dsentry) {
+            if(MAGIC_DSENTRY_NEXT(dsentry) != MAGIC_DSENTRY_NEXT(_magic_first_dsentry)) {
+                prev_dsentry = magic_dsentry_prev_lookup(dsentry);
+                assert(prev_dsentry != (struct _magic_dsentry *) MAGIC_ENOPTR && "Dsentry not found!");
+            }
+        }
+#endif
+
+        if(prev_dsentry) {
+            MAGIC_DSENTRY_NEXT(prev_dsentry) = MAGIC_DSENTRY_NEXT(dsentry);
+            dsentry_destroyed = 1;
+        }
+        else {
+            /* Remove the first dsentry atomically. */
+            next_dsentry = MAGIC_DSENTRY_NEXT(dsentry);
+            dsentry_destroyed = (MAGIC_CAS(&_magic_first_dsentry,
+                dsentry, next_dsentry) == dsentry);
+        }
+    } while(!dsentry_destroyed);
+
+#if MAGIC_DSENTRY_ALLOW_PREV
+    next_dsentry = MAGIC_DSENTRY_NEXT(dsentry);
+    if(next_dsentry) {
+        MAGIC_DSENTRY_PREV(next_dsentry) = MAGIC_DSENTRY_PREV(dsentry);
+    }
+    MAGIC_DSENTRY_PREV(dsentry) = NULL;
+#endif
+
+    dsentry->magic_number = MAGIC_DSENTRY_MNUM_NULL;
+    MAGIC_DSENTRY_NEXT(dsentry) = NULL;
+}
+
+/*===========================================================================*
+ *                       magic_destroy_obdsentry_by_addr                     *
+ *===========================================================================*/
+PUBLIC int magic_destroy_obdsentry_by_addr(void *data_ptr)
+{
+    struct _magic_dsentry _magic_dsentry_buff;
+    struct _magic_sentry *sentry;
+    struct _magic_dsentry *dsentry;
+    struct _magic_obdsentry *obdsentry;
+    int obflags = (MAGIC_STATE_DYNAMIC|MAGIC_STATE_OUT_OF_BAND);
+
+    MAGIC_MEM_WRAPPER_LBEGIN();
+
+    /* Lookup the obdsentry. */
+    sentry = magic_sentry_lookup_by_addr(data_ptr, &_magic_dsentry_buff);
+    if(!sentry || ((sentry->flags & obflags) != obflags)) {
+        MAGIC_MEM_WRAPPER_LEND();
+        return MAGIC_EINVAL;
+    }
+    dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
+    obdsentry = MAGIC_OBDSENTRY_FROM_DSENTRY(dsentry);
+
+    /* Destroy it and free obdsentry slot. */
+    magic_destroy_dsentry(dsentry, NULL);
+    MAGIC_OBDSENTRY_FREE(obdsentry);
+
+    MAGIC_MEM_WRAPPER_LEND();
+
+    return 0;
+}
+
+/*===========================================================================*
+ *                       magic_destroy_dsentry_set_ext_cb                    *
+ *===========================================================================*/
+PUBLIC void magic_destroy_dsentry_set_ext_cb(const magic_dsentry_cb_t cb)
+{
+    magic_destroy_dsentry_ext_cb = cb;
+}
+
+/*===========================================================================*
+ *                            magic_update_dsentry                           *
+ *===========================================================================*/
+PUBLIC int magic_update_dsentry(void* addr, struct _magic_type *type)
+{
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry* sentry;
+    size_t size, type_size;
+    int is_varsized = 0;
+    int num_vsa_elements = 0;
+
+    MAGIC_DSENTRY_LOCK();
+    MAGIC_DSENTRY_ALIVE_BLOCK_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+        if(sentry->address == addr) {
+            size = sentry->type->size;
+            type_size = type->size;
+
+            /* Catch variable-sized struct allocation. */
+            if(magic_type_alloc_needs_varsized_array(type, size, &num_vsa_elements)) {
+                is_varsized = 1;
+            }
+
+            if(size % type_size != 0 && !is_varsized) {
+                return MAGIC_EBADENT;
+            }
+            if(size == type_size && !is_varsized) {
+                sentry->type = type;
+            }
+            else {
+                struct _magic_type *array_type = &(dsentry->type);
+                MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(array_type, type,
+                    MAGIC_DSENTRY_TO_TYPE_ARR(dsentry), size, num_vsa_elements);
+                array_type->id = MAGIC_FAA(&_magic_types_next_id, 1);
+                assert(_magic_types_next_id < MAGIC_ID_MAX);
+                sentry->type = array_type;
+            }
+            return 0;
+        }
+    );
+    MAGIC_DSENTRY_UNLOCK();
+
+    return MAGIC_ENOENT;
+}
+
+/*===========================================================================*
+ *                              magic_stack_init                             *
+ *===========================================================================*/
+PUBLIC void magic_stack_init()
+{
+    struct _magic_obdsentry *obdsentry;
+    char **ptr;
+    size_t size;
+    void *initial_stack_bottom, *initial_stack_top;
+    unsigned long* word_ptr;
+    int argc;
+    char **argv;
+
+    assert(!_magic_first_stack_dsentry && !_magic_last_stack_dsentry);
+
+    /* Find initial stack bottom and top, this should be portable enough */
+    for (ptr = environ ; *ptr ; ptr++);
+    if (ptr == environ){
+        /* the environment is empty, and ptr still points to environ.
+         * decrement ptr twice: once to point at the argv terminator,
+         * and once to point to point at the last argument, which will be the stack bottom
+         */
+        ptr -= 2;
+    } else {
+        /* environment is not empty. decrement the pointer,
+         * because the for loop walked past the last env variable pointer.
+         */
+        ptr--;
+    }
+
+    if (*ptr) {
+        initial_stack_bottom = *ptr+strlen(*ptr)+1;
+        word_ptr = (unsigned long*) environ;
+        word_ptr--;
+        assert(*word_ptr == 0); /* argv terminator */
+        word_ptr--;
+        argc = 0;
+        while(*word_ptr != (unsigned long) argc) {
+            argc++;
+            word_ptr--;
+        }
+        argv = (char**) (word_ptr+1);
+        initial_stack_top = argv;
+    } else {
+        /* Environ and argv empty?. Resort to defaults. */
+        initial_stack_top = ptr;
+        initial_stack_bottom = environ;
+    }
+    size = (size_t)initial_stack_bottom - (size_t)initial_stack_top + 1;
+
+    /* Create the first stack dsentry. */
+    obdsentry = magic_create_obdsentry(initial_stack_top, MAGIC_VOID_TYPE,
+      size, MAGIC_STATE_STACK, MAGIC_ALLOC_INITIAL_STACK_NAME, NULL);
+    assert(obdsentry);
+    _magic_first_stack_dsentry = _magic_last_stack_dsentry = MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry);
+}
+
+/*===========================================================================*
+ *                        magic_stack_dsentries_create                       *
+ *===========================================================================*/
+PUBLIC void magic_stack_dsentries_create(
+    struct _magic_dsentry **prev_last_stack_dsentry, int num_dsentries,
+    /* struct _magic_dsentry *dsentry, struct _magic_type *type, void* data_ptr, char* function_name, char* name, */ ...)
+{
+    int i;
+    struct _magic_dsentry *dsentry;
+    struct _magic_type *type;
+    void* data_ptr;
+    char* function_name;
+    char* name;
+    char *min_data_ptr = NULL, *max_data_ptr = NULL;
+    va_list va;
+
+    assert(num_dsentries > 0);
+
+    MAGIC_DSENTRY_LOCK();
+    assert(_magic_first_stack_dsentry && "First stack dsentry not found!");
+    va_start(va, num_dsentries);
+    *prev_last_stack_dsentry = _magic_last_stack_dsentry;
+    for (i = 0 ; i < num_dsentries ; i++) {
+        dsentry = va_arg(va, struct _magic_dsentry *);
+        type = va_arg(va, struct _magic_type *);
+        data_ptr = va_arg(va, void *);
+        function_name = va_arg(va, char *);
+        name = va_arg(va, char *);
+        if (i == num_dsentries - 1) {
+            /* Return address. */
+            int *value_set = (void*) type;
+            data_ptr = MAGIC_FRAMEADDR_TO_RETADDR_PTR(data_ptr);
+            type = &(dsentry->type);
+            magic_create_dsentry(dsentry, data_ptr, MAGIC_VOID_TYPE, MAGIC_VOID_TYPE->size,
+                MAGIC_STATE_STACK | MAGIC_STATE_CONSTANT | MAGIC_STATE_ADDR_NOT_TAKEN,
+                name, function_name);
+            memcpy(type, &magic_default_ret_addr_type, sizeof(struct _magic_type));
+            type->contained_types = MAGIC_DSENTRY_TO_TYPE_ARR(dsentry);
+            type->contained_types[0] = MAGIC_VOID_TYPE;
+            type->value_set = value_set;
+            value_set[0] = 1;
+            value_set[1] = *((int *)data_ptr);
+
+            /* Safe to override the type non-atomically.
+            * The new type is only more restrictive, and nobody could
+            * have touched this stack dsentry in the meantime.
+            */
+            MAGIC_DSENTRY_TO_SENTRY(dsentry)->type = type;
+        } else {
+            /* Local variable. */
+            magic_create_dsentry(dsentry, data_ptr, type, type->size,
+                MAGIC_STATE_STACK, name, function_name);
+            if (!min_data_ptr || min_data_ptr > (char *) data_ptr) {
+                min_data_ptr = (char *) data_ptr;
+            }
+            if (!max_data_ptr || max_data_ptr < (char *) data_ptr) {
+                max_data_ptr = (char *) data_ptr;
+            }
+        }
+    }
+
+#if MAGIC_FORCE_DYN_MEM_ZERO_INIT
+    if (min_data_ptr && max_data_ptr) {
+        memset(min_data_ptr, 0, max_data_ptr - min_data_ptr + 1);
+    }
+#endif
+
+    _magic_last_stack_dsentry = dsentry;
+    MAGIC_DSENTRY_UNLOCK();
+
+    va_end(va);
+}
+
+/*===========================================================================*
+ *                        magic_stack_dsentries_destroy                      *
+ *===========================================================================*/
+PUBLIC void magic_stack_dsentries_destroy(
+    struct _magic_dsentry **prev_last_stack_dsentry, int num_dsentries,
+    /* struct _magic_dsentry *dsentry, */ ...)
+{
+    int i;
+    struct _magic_dsentry *dsentry;
+    va_list va;
+
+    assert(num_dsentries > 0);
+
+    MAGIC_MEM_WRAPPER_LBEGIN();
+
+    va_start(va, num_dsentries);
+    _magic_last_stack_dsentry = *prev_last_stack_dsentry;
+    for (i = 0 ; i < num_dsentries ; i++) {
+        dsentry = va_arg(va, struct _magic_dsentry *);
+        magic_destroy_dsentry(dsentry, NULL);
+    }
+    va_end(va);
+
+    MAGIC_MEM_WRAPPER_LEND();
+}
+
+/*===========================================================================*
+ *                         magic_create_dfunction                            *
+ *===========================================================================*/
+PUBLIC int magic_create_dfunction(struct _magic_dfunction *dfunction,
+    void *data_ptr, struct _magic_type *type, int flags,
+    char *name, char *parent_name)
+{
+    struct _magic_function *function = MAGIC_DFUNCTION_TO_FUNCTION(dfunction);
+
+    if(!type) {
+        type = MAGIC_VOID_TYPE;
+    }
+
+    memcpy(dfunction, &magic_default_dfunction, sizeof(struct _magic_dfunction));
+
+    assert(!(type->flags & MAGIC_TYPE_DYNAMIC) && "bad type!");
+
+    function->type = type;
+    function->flags |= flags;
+    function->address = data_ptr;
+    if(name) {
+        function->name = name;
+    }
+    if(parent_name) {
+        dfunction->parent_name = parent_name;
+    }
+    function->id = MAGIC_FAA(&_magic_functions_next_id, 1);
+    assert(_magic_functions_next_id < MAGIC_ID_MAX);
+
+    if(_magic_first_dfunction) {
+        assert(_magic_last_dfunction);
+        MAGIC_DFUNCTION_NEXT(_magic_last_dfunction) = dfunction;
+    }
+    else {
+        assert(!_magic_last_dfunction);
+        assert(_magic_dfunctions_num == 0);
+        _magic_first_dfunction = dfunction;
+    }
+    MAGIC_DFUNCTION_PREV(dfunction) = _magic_last_dfunction;
+    MAGIC_DFUNCTION_NEXT(dfunction) = NULL;
+    _magic_last_dfunction = dfunction;
+    _magic_dfunctions_num++;
+
+    assert(magic_check_dfunction(dfunction, 0) && "Bad magic dfunction created!");
+    magic_update_dfunction_ranges = 1;
+
+    return 0;
+}
+
+/*===========================================================================*
+ *                         magic_destroy_dfunction                           *
+ *===========================================================================*/
+PUBLIC void magic_destroy_dfunction(struct _magic_dfunction *dfunction)
+{
+    dfunction->magic_number = MAGIC_DFUNCTION_MNUM_NULL;
+    if(MAGIC_DFUNCTION_HAS_NEXT(dfunction)) {
+        MAGIC_DFUNCTION_PREV(MAGIC_DFUNCTION_NEXT(dfunction)) = MAGIC_DFUNCTION_PREV(dfunction);
+    }
+    else {
+        _magic_last_dfunction = MAGIC_DFUNCTION_PREV(dfunction);
+    }
+    if(MAGIC_DFUNCTION_HAS_PREV(dfunction)) {
+        MAGIC_DFUNCTION_NEXT(MAGIC_DFUNCTION_PREV(dfunction)) = MAGIC_DFUNCTION_NEXT(dfunction);
+    }
+    else {
+        _magic_first_dfunction = MAGIC_DFUNCTION_NEXT(dfunction);
+    }
+    MAGIC_DFUNCTION_NEXT(dfunction) = NULL;
+    MAGIC_DFUNCTION_PREV(dfunction) = NULL;
+    _magic_dfunctions_num--;
+    if(_magic_dfunctions_num == 0) {
+        assert(!_magic_first_dfunction && !_magic_last_dfunction);
+    }
+    else {
+        assert(_magic_first_dfunction && _magic_last_dfunction);
+    }
+}
+
+/*===========================================================================*
+ *                          magic_create_sodesc                              *
+ *===========================================================================*/
+PUBLIC int magic_create_sodesc(struct _magic_sodesc *sodesc)
+{
+    if(_magic_first_sodesc) {
+        assert(_magic_last_sodesc);
+        MAGIC_SODESC_NEXT(_magic_last_sodesc) = sodesc;
+    }
+    else {
+        assert(!_magic_last_sodesc);
+        assert(_magic_sodescs_num == 0);
+        _magic_first_sodesc = sodesc;
+    }
+    MAGIC_SODESC_PREV(sodesc) = _magic_last_sodesc;
+    MAGIC_SODESC_NEXT(sodesc) = NULL;
+    _magic_last_sodesc = sodesc;
+    _magic_sodescs_num++;
+
+    return 0;
+}
+
+/*===========================================================================*
+ *                          magic_destroy_sodesc                             *
+ *===========================================================================*/
+PUBLIC int magic_destroy_sodesc(struct _magic_sodesc *sodesc)
+{
+    /*
+     * NB!: This function requires the calling thread to already
+     * hold the DSENTRY and DFUNCTION locks.
+     */
+    int ret;
+    const char *name;
+    struct _magic_dsentry *prev_dsentry, *dsentry, *last_dsentry;
+    struct _magic_sentry *sentry;
+    struct _magic_dfunction *dfunction, *last_dfunction;
+
+    /*
+     * Time to destroy all the dsentries and dfunctions
+     * linked to the descriptor.
+     */
+    name = sodesc->lib.name;
+    last_dsentry = NULL;
+    MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry,
+        dsentry, sentry,
+        if (last_dsentry)
+            magic_destroy_dsentry(last_dsentry, NULL);
+        last_dsentry = dsentry->parent_name == name ? dsentry : NULL;
+    );
+    if (last_dsentry)
+        magic_destroy_dsentry(last_dsentry, NULL);
+    last_dfunction = NULL;
+    MAGIC_DFUNCTION_ITER(_magic_first_dfunction, dfunction,
+        if (last_dfunction)
+            magic_destroy_dfunction(last_dfunction);
+        last_dfunction = dfunction->parent_name == name ? dfunction : NULL;
+    );
+    if(last_dfunction) magic_destroy_dfunction(last_dfunction);
+
+    /* Now get rid of the descriptor. */
+    if (MAGIC_SODESC_HAS_NEXT(sodesc)) {
+        MAGIC_SODESC_PREV(MAGIC_SODESC_NEXT(sodesc)) =
+            MAGIC_SODESC_PREV(sodesc);
+    }
+    else {
+        _magic_last_sodesc = MAGIC_SODESC_PREV(sodesc);
+    }
+    if (MAGIC_SODESC_HAS_PREV(sodesc)) {
+        MAGIC_SODESC_NEXT(MAGIC_SODESC_PREV(sodesc)) =
+            MAGIC_SODESC_NEXT(sodesc);
+    }
+    else {
+        _magic_first_sodesc = MAGIC_SODESC_NEXT(sodesc);
+    }
+    MAGIC_SODESC_NEXT(sodesc) = NULL;
+    MAGIC_SODESC_PREV(sodesc) = NULL;
+    _magic_sodescs_num--;
+    if (_magic_sodescs_num == 0) {
+        assert(!_magic_first_sodesc && !_magic_last_sodesc);
+    }
+    else {
+        assert(_magic_first_sodesc && _magic_last_sodesc);
+    }
+
+    /*
+     * Unmap the memory area that contained the dsentries and dfunctions
+     * of this descriptor.
+     */
+    ret = munmap(sodesc->lib.alloc_address, sodesc->lib.alloc_size);
+    assert(ret == 0 && "Unable to unmap SODESC memory segment!");
+
+    return 0;
+}
+
+/*===========================================================================*
+ *                          magic_create_dsodesc                             *
+ *===========================================================================*/
+PUBLIC int magic_create_dsodesc(struct _magic_dsodesc *dsodesc)
+{
+    /*
+     * NB!: This function requires the calling thread to already
+     * hold the DSODESC lock.
+     */
+    if (_magic_first_dsodesc) {
+        assert(_magic_last_dsodesc);
+        MAGIC_DSODESC_NEXT(_magic_last_dsodesc) = dsodesc;
+    }
+    else {
+        assert(!_magic_last_dsodesc);
+        assert(_magic_dsodescs_num == 0);
+        _magic_first_dsodesc = dsodesc;
+    }
+    MAGIC_DSODESC_PREV(dsodesc) = _magic_last_dsodesc;
+    MAGIC_DSODESC_NEXT(dsodesc) = NULL;
+    _magic_last_dsodesc = dsodesc;
+    _magic_dsodescs_num++;
+
+    return 0;
+}
+
+/*===========================================================================*
+ *                          magic_destroy_dsodesc                            *
+ *===========================================================================*/
+PUBLIC int magic_destroy_dsodesc(struct _magic_dsodesc *dsodesc)
+{
+    /*
+     * NB!: This function requires the calling thread to already
+     * hold the DSENTRY, DFUNCTION and DSODESC locks.
+     */
+    int ret;
+    const char *name;
+    struct _magic_dsentry *prev_dsentry, *dsentry, *last_dsentry;
+    struct _magic_sentry *sentry;
+    struct _magic_dfunction *dfunction, *last_dfunction;
+
+    dsodesc->ref_count--;
+    /* Don't destroy the DSO descriptor quite yet, we still have references. */
+    if (dsodesc->ref_count > 0) {
+        return dsodesc->ref_count;
+    }
+
+    /*
+     * Time to destroy all the dsentries and dfunctions
+     * linked to the descriptor.
+     */
+    name = dsodesc->lib.name;
+    last_dsentry = NULL;
+    MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry,
+        dsentry, sentry,
+        if (last_dsentry)
+            magic_destroy_dsentry(last_dsentry, NULL);
+        last_dsentry = dsentry->parent_name == name ? dsentry : NULL;
+    );
+    if (last_dsentry)
+        magic_destroy_dsentry(last_dsentry, NULL);
+    last_dfunction = NULL;
+    MAGIC_DFUNCTION_ITER(_magic_first_dfunction, dfunction,
+        if (last_dfunction)
+            magic_destroy_dfunction(last_dfunction);
+        last_dfunction = dfunction->parent_name == name ? dfunction : NULL;
+    );
+    if (last_dfunction)
+        magic_destroy_dfunction(last_dfunction);
+
+    /* Now get rid of the descriptor. */
+    if (MAGIC_DSODESC_HAS_NEXT(dsodesc)) {
+        MAGIC_DSODESC_PREV(MAGIC_DSODESC_NEXT(dsodesc)) =
+            MAGIC_DSODESC_PREV(dsodesc);
+    }
+    else {
+        _magic_last_dsodesc = MAGIC_DSODESC_PREV(dsodesc);
+    }
+    if (MAGIC_DSODESC_HAS_PREV(dsodesc)) {
+        MAGIC_DSODESC_NEXT(MAGIC_DSODESC_PREV(dsodesc)) =
+            MAGIC_DSODESC_NEXT(dsodesc);
+    }
+    else {
+        _magic_first_dsodesc = MAGIC_DSODESC_NEXT(dsodesc);
+    }
+    MAGIC_DSODESC_NEXT(dsodesc) = NULL;
+    MAGIC_DSODESC_PREV(dsodesc) = NULL;
+    _magic_dsodescs_num--;
+    if (_magic_dsodescs_num == 0) {
+        assert(!_magic_first_dsodesc && !_magic_last_dsodesc);
+    }
+    else {
+        assert(_magic_first_dsodesc && _magic_last_dsodesc);
+    }
+
+    /*
+     * Unmap the memory area that contained the dsentries and dfunctions
+     * of this descriptor.
+     */
+    ret = munmap(dsodesc->lib.alloc_address, dsodesc->lib.alloc_size);
+    assert(ret == 0 && "Unable to unmap DSODESC memory segment!");
+
+    return 0; /* no more references, descriptor is gone. */
+}
+
+/*===========================================================================*
+ *                              magic_alloc                                  *
+ *===========================================================================*/
+PUBLIC void *magic_alloc(__MA_ARGS__ void *ptr, size_t size, int flags)
+{
+    int ret;
+    void *data_ptr;
+    struct _magic_dsentry *dsentry;
+
+    if(ptr == NULL) {
+        return NULL;
+    }
+    data_ptr = MAGIC_PTR_TO_DATA(ptr);
+    dsentry = MAGIC_PTR_TO_DSENTRY(ptr);
+    /* Catch pool allocations and update the name & flags */
+    if (MAGIC_MEMPOOL_MGMT_IS_ACTIVE() && !(flags & MAGIC_STATE_MEMBLOCK)) {
+        flags |= MAGIC_STATE_MEMPOOL;
+        name = MAGIC_MEMPOOL_GET_NAME();
+    }
+    ret = magic_create_dsentry(dsentry, data_ptr, type, size, flags, name, parent_name);
+    MAGIC_MEM_PRINTF("magic_alloc: ret = magic_create_dsentry(dsentry, data_ptr, type, size, flags, NULL, NULL) <-> %d = magic_create_dsentry(0x%08x, 0x%08x, 0x%08x, %d, 0x%08x, NULL, NULL)\n", ret, (unsigned) dsentry, (unsigned) data_ptr, type, size, flags);
+    if(ret < 0) {
+        return MAGIC_MEM_FAILED;
+    }
+
+    /* this way we skip the memory pool blocks -they are not real allocations and should not be logged */
+    if (!(flags & MAGIC_STATE_MEMBLOCK)) {
+        MAGIC_MEM_DEBUG_ALLOC(ptr, (MAGIC_SIZE_TO_REAL(size)));
+    }
+
+#if DEBUG
+    MAGIC_MEM_PRINTF("magic_alloc: magic_create_dsentry created sentry: ");
+    MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
+    MAGIC_MEM_PRINTF("\n");
+#endif
+
+    MAGIC_MEM_PRINTF("magic_alloc: return 0x%08x\n", (unsigned) data_ptr);
+
+    return data_ptr;
+}
+
+/*===========================================================================*
+ *                           magic_malloc_positioned                         *
+ *===========================================================================*/
+PUBLIC void *magic_malloc_positioned(__MA_ARGS__ size_t size, void *ptr)
+{
+    void *data_ptr;
+    int dsentry_flags = MAGIC_STATE_HEAP;
+
+#if MAGIC_FORCE_DYN_MEM_ZERO_INIT
+    assert(!_magic_vars->fake_malloc);
+    do {
+        return magic_calloc(__MA_VALUES__ size, 1);
+    } while(0);
+#endif
+
+    MAGIC_MEM_WRAPPER_BEGIN();
+
+    if(size > 0) {
+        if (!ptr || !_magic_vars->fake_malloc) {
+            /*
+             * Check the external callback first.
+             */
+            if (magic_mem_heap_alloc_cb)
+                ptr = magic_mem_heap_alloc_cb(MAGIC_SIZE_TO_REAL(size) + magic_asr_get_padding_size(MAGIC_STATE_HEAP), name, parent_name);
+
+            if (!ptr)
+                ptr = malloc(MAGIC_SIZE_TO_REAL(size) + magic_asr_get_padding_size(MAGIC_STATE_HEAP));
+            MAGIC_MEM_PRINTF("magic_malloc: ptr = malloc(size) <-> 0x%08x = malloc(%d)\n", (unsigned) ptr, MAGIC_SIZE_TO_REAL(size));
+        }
+        data_ptr = magic_alloc(__MA_VALUES__ ptr, size, dsentry_flags);
+        if (data_ptr == MAGIC_MEM_FAILED) {
+            /*
+             * XXX: This doesn't seem likely to happen. However, if it does,
+             * we need to distinguish between regular malloc() memory
+             * and super-objects. See llvm/shared/libst/include/heap.h for
+             * more information.
+             */
+            free(ptr);
+            data_ptr = NULL;
+            errno = ENOMEM;
+        }
+        magic_heap_end = ((char *)sbrk(0)) - 1;
+    }
+    else {
+        data_ptr = NULL;
+    }
+
+    MAGIC_MEM_WRAPPER_END();
+
+    return data_ptr;
+}
+
+/*===========================================================================*
+ *                               magic_malloc                                *
+ *===========================================================================*/
+PUBLIC void *magic_malloc(__MA_ARGS__ size_t size)
+{
+    return magic_malloc_positioned(__MA_VALUES__ size, NULL);
+}
+
+/*===========================================================================*
+ *                               magic_calloc                                *
+ *===========================================================================*/
+PUBLIC void *magic_calloc(__MA_ARGS__ size_t nmemb, size_t size)
+{
+    void *ptr = NULL, *data_ptr;
+    size_t real_size;
+    int dsentry_flags = MAGIC_STATE_HEAP;
+
+    MAGIC_MEM_WRAPPER_BEGIN();
+
+    if(size > 0) {
+        real_size = MAGIC_SIZE_TO_REAL(size*nmemb);
+        /*
+         * Check the external callback first.
+         */
+        if (magic_mem_heap_alloc_cb)
+            ptr = magic_mem_heap_alloc_cb(real_size + magic_asr_get_padding_size(MAGIC_STATE_HEAP), name, parent_name);
+
+        if (!ptr)
+            ptr = calloc(real_size + magic_asr_get_padding_size(MAGIC_STATE_HEAP), 1);
+        MAGIC_MEM_PRINTF("magic_calloc: ptr = calloc(nmemb, size) <-> 0x%08x = calloc(%d, %d)\n", (unsigned) ptr, nmemb, real_size);
+        data_ptr = magic_alloc(__MA_VALUES__ ptr, size*nmemb, dsentry_flags);
+        if(data_ptr == MAGIC_MEM_FAILED) {
+            /*
+             * XXX: This doesn't seem likely to happen. However, if it does,
+             * we need to distinguish between regular malloc() memory
+             * and super-objects. See llvm/shared/libst/include/heap.h for
+             * more information.
+             */
+            free(ptr);
+            data_ptr = NULL;
+            errno = ENOMEM;
+        }
+        magic_heap_end = ((char*)sbrk(0))-1;
+    }
+    else {
+        data_ptr = NULL;
+    }
+
+    MAGIC_MEM_WRAPPER_END();
+
+    return data_ptr;
+}
+
+/*===========================================================================*
+ *                                magic_free                                 *
+ *===========================================================================*/
+PUBLIC void magic_free(__MD_ARGS__ void *data_ptr)
+{
+    void *ptr;
+    int ret;
+
+    MAGIC_MEM_WRAPPER_BEGIN();
+
+    if(data_ptr) {
+        ptr = MAGIC_PTR_FROM_DATA(data_ptr);
+
+        /* Check for legitimate non-indexed chunks of memory and skip. */
+        if((!magic_libcommon_active || !MAGIC_USE_DYN_MEM_WRAPPERS)
+            && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr))) {
+            MAGIC_MEM_WRAPPER_END();
+            free(data_ptr);
+            return;
+        }
+
+        MAGIC_MEM_PRINTF("magic_free: magic_free(0x%08x) / free(0x%08x)\n", (unsigned) data_ptr, (unsigned) ptr);
+        assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_HEAP) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
+
+        if(magic_allow_dead_dsentries) {
+            ret = magic_update_dsentry_state(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_DSENTRY_MSTATE_DEAD);
+            assert(ret == 0 && "Bad free!");
+        }
+        else {
+            MAGIC_DSENTRY_LOCK();
+            magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), NULL);
+            ret = magic_free_dsentry(MAGIC_PTR_TO_DSENTRY(ptr));
+            assert(ret == 0 && "Bad free!");
+            MAGIC_DSENTRY_UNLOCK();
+        }
+    }
+
+    MAGIC_MEM_WRAPPER_END();
+}
+
+/*===========================================================================*
+ *                              magic_realloc                                *
+ *===========================================================================*/
+PUBLIC void *magic_realloc(__MA_ARGS__ void *data_ptr, size_t size)
+{
+    void *ptr, *new_ptr, *new_data_ptr;
+    size_t old_size;
+
+    if(!data_ptr) {
+        return magic_malloc(__MA_VALUES__ size);
+    }
+    if(size == 0) {
+        magic_free(__MD_VALUES_DEFAULT__ data_ptr);
+        return NULL;
+    }
+
+    ptr = MAGIC_PTR_FROM_DATA(data_ptr);
+    new_data_ptr = magic_malloc(__MA_VALUES__ size);
+    if(!new_data_ptr) {
+        return NULL;
+    }
+    new_ptr = MAGIC_PTR_FROM_DATA(new_data_ptr);
+    assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_HEAP) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
+    MAGIC_MEM_PRINTF("magic_realloc: ptr = realloc(ptr, size) <-> 0x%08x = realloc(0x%08x, %d)\n", (unsigned) new_ptr, (unsigned) ptr, MAGIC_SIZE_TO_REAL(size));
+
+    old_size = MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr))->type->size;
+    memcpy(new_data_ptr, data_ptr, old_size < size ? old_size : size);
+    magic_free(__MD_VALUES_DEFAULT__ data_ptr);
+
+    return new_data_ptr;
+}
+
+/*===========================================================================*
+ *                           magic_posix_memalign                            *
+ *===========================================================================*/
+PUBLIC int magic_posix_memalign(__MA_ARGS__ void **memptr, size_t alignment, size_t size)
+{
+    int ret = 0;
+    void *ptr = NULL, *data_ptr;
+    int dsentry_flags = MAGIC_STATE_HEAP;
+
+    MAGIC_MEM_WRAPPER_BEGIN();
+
+    if(size > 0) {
+        /*
+         * Check the external callback first.
+         */
+        if (magic_mem_heap_alloc_cb)
+            ptr = magic_mem_heap_alloc_cb(MAGIC_SIZE_TO_REAL(size), name, parent_name);
+
+        if (!ptr)
+            ret = posix_memalign(&ptr, alignment, MAGIC_SIZE_TO_REAL(size));
+        MAGIC_MEM_PRINTF("magic_posix_memalign: ret = posix_memalign(ptr, alignment, size) <-> %d = posix_memalign(%p, %d, %d)\n", ret, ptr, alignment, MAGIC_SIZE_TO_REAL(size));
+        if(ret == 0) {
+            data_ptr = magic_alloc(__MA_VALUES__ ptr, size, dsentry_flags);
+            if(data_ptr == MAGIC_MEM_FAILED) {
+                /*
+                 * XXX: This doesn't seem likely to happen. However, if it does,
+                 * we need to distinguish between regular malloc() memory
+                 * and super-objects. See llvm/shared/libst/include/heap.h for
+                 * more information.
+                 */
+                free(ptr);
+                ret = ENOMEM;
+            }
+            else {
+                *memptr = data_ptr;
+#if MAGIC_FORCE_DYN_MEM_ZERO_INIT
+                memset(data_ptr, 0, size);
+#endif
+            }
+            magic_heap_end = ((char*)sbrk(0))-1;
+        }
+    }
+    else {
+        ret = EINVAL;
+    }
+
+    MAGIC_MEM_WRAPPER_END();
+
+    return ret;
+}
+
+#ifndef __MINIX
+/*===========================================================================*
+ *                              magic_valloc                                 *
+ *===========================================================================*/
+PUBLIC void *magic_valloc(__MA_ARGS__ size_t size)
+{
+    return magic_memalign(__MA_VALUES__ MAGIC_PAGE_SIZE, size);
+}
+
+/*===========================================================================*
+ *                              magic_memalign                               *
+ *===========================================================================*/
+PUBLIC void *magic_memalign(__MA_ARGS__ size_t boundary, size_t size)
+{
+    void *ptr;
+    int ret = magic_posix_memalign(__MA_VALUES__ &ptr, boundary, size);
+    if(ret != 0) {
+        return NULL;
+    }
+    return ptr;
+}
+
+#endif
+
+/*===========================================================================*
+ *                           magic_mmap_positioned                           *
+ *===========================================================================*/
+PUBLIC void *magic_mmap_positioned(__MA_ARGS__ void *start, size_t length, int prot, int flags,
+    int fd, off_t offset, struct _magic_dsentry *cached_dsentry)
+{
+    void *ptr, *data_ptr, *aligned_start, *aligned_ptr;
+    void *new_ptr, *new_start;
+    int dsentry_flags = MAGIC_STATE_MAP;
+    size_t alloc_length;
+    size_t page_size = MAGIC_PAGE_SIZE;
+    int padding_type, padding_size;
+    static THREAD_LOCAL int magic_is_first_mmap = 1;
+
+    MAGIC_MEM_WRAPPER_BEGIN();
+
+    if (flags & MAP_FIXED) {
+        /* Allow safe overmapping. */
+        struct _magic_sentry *sentry = magic_sentry_lookup_by_range(start, NULL);
+        if (sentry && sentry == magic_sentry_lookup_by_range((char*)start+length-1, NULL))
+            return mmap(start, length, prot, flags, fd, offset);
+    }
+    assert(!(flags & MAP_FIXED) && "MAP_FIXED may override existing mapping, currently not implemented!");
+    if (length > 0) {
+        if (magic_is_first_mmap) {
+            magic_is_first_mmap = 0;
+            padding_type = MAGIC_STATE_MAP | MAGIC_ASR_FLAG_INIT;
+        } else {
+            padding_type = MAGIC_STATE_MAP;
+        }
+        padding_size = start ? 0 : magic_asr_get_padding_size(padding_type);
+
+        assert(MAGIC_SIZE_TO_REAL(length) <= page_size + length);
+        aligned_start = start ? ((char *)start) - page_size : NULL;
+        alloc_length = length + (length % page_size == 0 ? 0 : page_size - (length % page_size));
+#if 0
+        if (_magic_vars->do_skip_mmap) {
+            ptr = cached_dsentry ? ((char *)cached_dsentry) - (padding_size + page_size - MAGIC_SIZE_TO_REAL(0)) : NULL;
+        } else
+#endif
+        if (!(flags & MAP_ANONYMOUS) && !(flags & MAP_SHARED) && ((prot & magic_mmap_dsentry_header_prot) == magic_mmap_dsentry_header_prot)) {
+            ptr = mmap(aligned_start, page_size + alloc_length + padding_size, prot, flags, fd, offset);
+        }
+        else {
+            /* Preallocate memory for metadata + data. */
+            ptr = mmap(aligned_start, page_size + alloc_length + padding_size, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS | MAP_PRIVATE | (flags & MAP_FIXED), -1, 0);
+
+            /* Remap the data part the way the caller wants us to. */
+            if (ptr != MAP_FAILED) {
+                new_start = ((char *)ptr) + page_size;
+                new_ptr = mmap(new_start, length, prot, flags | MAP_FIXED, fd, offset);
+                if (new_ptr == MAP_FAILED) {
+                    munmap(ptr, page_size + alloc_length);
+                    ptr = MAP_FAILED;
+                }
+            }
+        }
+        aligned_ptr = ptr;
+        MAGIC_MEM_PRINTF("magic_mmap: ptr = mmap(start, length, prot, flags, fd, offset) <-> 0x%08x = mmap(0x%08x, %d, 0x%08x, 0x%08x, %d, %d)\n", (unsigned) aligned_ptr, aligned_start, page_size + length, prot, flags, fd, offset);
+        if (ptr != MAP_FAILED) {
+            ptr = ((char *)ptr) + padding_size + page_size - MAGIC_SIZE_TO_REAL(0);
+        }
+        else {
+            ptr = NULL;
+        }
+        if (flags & MAP_SHARED)
+            dsentry_flags |= MAGIC_STATE_SHM;
+        data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, dsentry_flags);
+        if (data_ptr == MAGIC_MEM_FAILED) {
+            munmap(aligned_ptr, page_size + length);
+            data_ptr = NULL;
+            errno = ENOMEM;
+        }
+        if (!data_ptr) {
+            errno = ENOMEM;
+            data_ptr = MAP_FAILED;
+        } else {
+            MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = flags;
+            MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = prot;
+            MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->ext = (void *) padding_size;
+        }
+    }
+    else {
+        data_ptr = MAP_FAILED;
+        errno = EINVAL;
+    }
+
+    MAGIC_MEM_WRAPPER_END();
+
+    return data_ptr;
+}
+
+/*===========================================================================*
+ *                               magic_mmap                                  *
+ *===========================================================================*/
+PUBLIC void *magic_mmap(__MA_ARGS__ void *start, size_t length, int prot, int flags,
+    int fd, off_t offset)
+{
+    return magic_mmap_positioned(__MA_VALUES__ start, length, prot, flags, fd, offset, NULL);
+}
+
+/*===========================================================================*
+ *                              magic_munmap                                 *
+ *===========================================================================*/
+PUBLIC int magic_munmap(__MD_ARGS__ void *data_ptr, size_t length)
+{
+    int ret;
+    void *ptr, *aligned_ptr;
+    struct _magic_sentry *sentry;
+    size_t alloc_length, old_size;
+    size_t page_size = MAGIC_PAGE_SIZE;
+
+    MAGIC_MEM_WRAPPER_BEGIN();
+
+    if(data_ptr) {
+        ptr = MAGIC_PTR_FROM_DATA(data_ptr);
+
+        /* Check for legitimate non-indexed chunks of memory and skip. */
+        if((!magic_libcommon_active || !MAGIC_USE_DYN_MEM_WRAPPERS)
+            && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr))) {
+            MAGIC_MEM_WRAPPER_END();
+            return munmap(data_ptr, length);
+        }
+
+        sentry = MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr));
+        aligned_ptr = ((char*)data_ptr) - page_size;
+        MAGIC_MEM_PRINTF("magic_munmap: magic_munmap(0x%08x, %d) / unmap(0x%08x, %d)\n", (unsigned) data_ptr, length, (unsigned) aligned_ptr, page_size+length);
+        assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_MAP) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
+        old_size = MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr))->type->size;
+        alloc_length = length + (length % page_size == 0 ? 0 : page_size-(length % page_size));
+
+        if(alloc_length != old_size) {
+            assert(alloc_length >= old_size && "Partial unmapping not supported!");
+            ret = -1;
+            errno = EINVAL;
+        }
+        else {
+            if(magic_allow_dead_dsentries) {
+                ret = magic_update_dsentry_state(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_DSENTRY_MSTATE_DEAD);
+                assert(ret == 0 && "Bad munmap!");
+            }
+            else {
+                MAGIC_DSENTRY_LOCK();
+                magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), NULL);
+                ret = magic_free_dsentry(MAGIC_PTR_TO_DSENTRY(ptr));
+                assert(ret == 0 && "Bad munmap!");
+                MAGIC_DSENTRY_UNLOCK();
+            }
+        }
+    }
+    else {
+        ret = -1;
+        errno = EINVAL;
+    }
+
+    MAGIC_MEM_WRAPPER_END();
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                               magic_brk                                   *
+ *===========================================================================*/
+PUBLIC int magic_brk(__MA_ARGS__ void *addr)
+{
+    void *ptr;
+    void *break_addr;
+    int ret;
+
+    MAGIC_MEM_PRINTF("magic_brk: Warning: somebody calling magic_brk()!");
+    MAGIC_MEM_WRAPPER_LBLOCK( break_addr = sbrk(0); );
+    if(addr >= break_addr) {
+        ptr = magic_sbrk(__MA_VALUES__ (char*)addr - (char*)break_addr);
+        ret = (ptr == (void*) -1 ? -1 : 0);
+        if(ret == -1) {
+            errno = ENOMEM;
+        }
+    }
+    else {
+        magic_free(__MD_VALUES_DEFAULT__ addr);
+        ret = 0;
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                              magic_sbrk                                   *
+ *===========================================================================*/
+PUBLIC void *magic_sbrk(__MA_ARGS__ intptr_t increment)
+{
+    void *ptr;
+
+    if(increment == 0) {
+        MAGIC_MEM_WRAPPER_LBLOCK( ptr = sbrk(0); );
+    }
+    else {
+        MAGIC_MEM_PRINTF("magic_sbrk: Warning: somebody calling magic_sbrk(), resorting to magic_malloc()!");
+        ptr = magic_malloc(__MA_VALUES__ increment);
+    }
+
+    return ptr;
+}
+
+#ifndef __MINIX
+/*===========================================================================*
+ *                             magic_shmat                                   *
+ *===========================================================================*/
+PUBLIC void *magic_shmat(__MA_ARGS__ int shmid, const void *shmaddr, int shmflg)
+{
+    void *ptr, *data_ptr, *aligned_shmaddr, *aligned_ptr;
+    void *new_ptr, *new_shmaddr;
+    size_t size;
+    struct shmid_ds buf;
+    int ret, flags;
+    size_t page_size = MAGIC_PAGE_SIZE;
+
+    MAGIC_MEM_WRAPPER_BEGIN();
+
+    assert(!(shmflg & SHM_REMAP) && "Linux-specific SHM_REMAP not supported!");
+    ret = shmctl(shmid, IPC_STAT, &buf);
+    if (ret == -1) {
+        MAGIC_MEM_WRAPPER_END();
+        return NULL;
+    }
+    size = buf.shm_segsz;
+    if (size > 0) {
+        assert(size % page_size == 0);
+        assert(MAGIC_SIZE_TO_REAL(size) <= size + page_size);
+        if (shmaddr && (shmflg & SHM_RND)) {
+            unsigned long shmlba = SHMLBA;
+            shmflg &= ~SHM_RND;
+            shmaddr = (void *) ((((unsigned long)shmaddr) / shmlba) * shmlba);
+        }
+
+        /* Preallocate memory for metadata + data. */
+        aligned_shmaddr = shmaddr ? ((char *)shmaddr) - page_size : NULL;
+        flags = MAP_ANONYMOUS | MAP_PRIVATE | (aligned_shmaddr ? MAP_FIXED : 0);
+        ptr = mmap(aligned_shmaddr, page_size + size, magic_mmap_dsentry_header_prot, flags, -1, 0);
+
+        /* Remap the data part the way the caller wants us to. */
+        if (ptr != MAP_FAILED) {
+            new_shmaddr = ((char *)ptr) + page_size;
+            munmap(new_shmaddr, size);
+            new_ptr = shmat(shmid, new_shmaddr, shmflg);
+            if(new_ptr == (void *) -1) {
+                munmap(ptr, page_size);
+                ptr = MAP_FAILED;
+            }
+        }
+        aligned_ptr = ptr;
+        MAGIC_MEM_PRINTF("magic_shmat: ptr = shmat(shmid, shmaddr, shmflg) <-> 0x%08x = shmat(%d, 0x%08x, 0x%08x)\n", (unsigned) aligned_ptr, shmid, aligned_shmaddr, shmflg);
+        if (ptr != MAP_FAILED) {
+            ptr = ((char *)ptr) + page_size - MAGIC_SIZE_TO_REAL(0);
+        }
+        else {
+            ptr = NULL;
+        }
+        data_ptr = magic_alloc(__MA_VALUES__ ptr, size, MAGIC_STATE_SHM | MAGIC_STATE_DETACHED);
+        if (data_ptr == MAGIC_MEM_FAILED) {
+            munmap(aligned_ptr, page_size);
+            munmap(new_ptr, size);
+            data_ptr = (void *) -1;
+            errno = ENOMEM;
+        }
+        else {
+            MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_shmat_flags = shmflg;
+            MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_shmat_shmid = shmid;
+        }
+    }
+    else {
+        data_ptr = (void *) -1;
+        errno = EINVAL;
+    }
+
+    MAGIC_MEM_WRAPPER_END();
+
+    return data_ptr;
+}
+
+/*===========================================================================*
+ *                             magic_shmdt                                   *
+ *===========================================================================*/
+PUBLIC int magic_shmdt(__MD_ARGS__ const void *data_ptr)
+{
+    int ret;
+    void *ptr, *aligned_ptr;
+    size_t page_size = MAGIC_PAGE_SIZE;
+
+    MAGIC_MEM_WRAPPER_LBEGIN();
+
+    if (data_ptr) {
+        ptr = MAGIC_PTR_FROM_DATA(data_ptr);
+
+        /* Check for legitimate non-indexed chunks of memory and skip. */
+        if ((!magic_libcommon_active || !MAGIC_USE_DYN_MEM_WRAPPERS)
+            && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr))) {
+            MAGIC_MEM_WRAPPER_LEND();
+            return shmdt(data_ptr);
+        }
+
+        aligned_ptr = ((char*)data_ptr) - page_size;
+        MAGIC_MEM_PRINTF("magic_shmdt: magic_shmdt(0x%08x) / shmdt(0x%08x)\n", (unsigned) data_ptr, (unsigned) aligned_ptr);
+        assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_SHM) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
+        ret = shmdt(data_ptr);
+        if (ret == 0) {
+            magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), NULL);
+            munmap(aligned_ptr, page_size);
+        }
+    }
+    else {
+        ret = -1;
+        errno = EINVAL;
+    }
+
+    MAGIC_MEM_WRAPPER_LEND();
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                               magic_mmap64                                *
+ *===========================================================================*/
+PUBLIC void *magic_mmap64(__MA_ARGS__ void *start, size_t length, int prot, int flags,
+    int fd, off_t pgoffset)
+{
+    void *ptr, *data_ptr, *aligned_start, *aligned_ptr;
+    void *new_ptr, *new_start;
+    int dsentry_flags = MAGIC_STATE_MAP;
+    size_t alloc_length;
+    size_t page_size = MAGIC_PAGE_SIZE;
+
+    MAGIC_MEM_WRAPPER_BEGIN();
+
+    if (flags & MAP_FIXED) {
+       /* Allow safe overmapping. */
+       struct _magic_sentry *sentry = magic_sentry_lookup_by_range(start, NULL);
+       if (sentry && sentry == magic_sentry_lookup_by_range((char*)start+length-1, NULL))
+            return mmap64(start, length, prot, flags, fd, pgoffset);
+    }
+    assert(!(flags & MAP_FIXED) && "MAP_FIXED may override existing mapping, currently not implemented!");
+    if(length > 0) {
+        assert(MAGIC_SIZE_TO_REAL(length) <= page_size+length);
+        aligned_start = start ? ((char*)start) - page_size : NULL;
+        alloc_length = length + (length % page_size == 0 ? 0 : page_size-(length % page_size));
+        if((flags & MAP_ANONYMOUS) && !(flags & MAP_SHARED) && ((prot & magic_mmap_dsentry_header_prot) == magic_mmap_dsentry_header_prot)) {
+            ptr = mmap64(aligned_start, page_size+length, prot, flags, fd, pgoffset);
+        }
+        else {
+            /* Preallocate memory for metadata + data. */
+            ptr = mmap64(aligned_start, page_size+alloc_length, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS|MAP_PRIVATE|(flags & MAP_FIXED), -1, 0);
+
+            /* Remap the data part the way the caller wants us to. */
+            if(ptr != MAP_FAILED) {
+                new_start = ((char*)ptr) + page_size;
+                new_ptr = mmap64(new_start, length, prot, flags|MAP_FIXED, fd, pgoffset);
+                if(new_ptr == MAP_FAILED) {
+                    munmap(ptr, page_size+alloc_length);
+                    ptr = MAP_FAILED;
+                }
+            }
+        }
+        aligned_ptr = ptr;
+        MAGIC_MEM_PRINTF("magic_mmap64: ptr = mmap64(start, length, prot, flags, fd, pgoffset) <-> 0x%08x = mmap64(0x%08x, %d, 0x%08x, 0x%08x, %d, %d)\n", (unsigned) aligned_ptr, aligned_start, page_size+length, prot, flags, fd, pgoffset);
+        if(ptr != MAP_FAILED) {
+            ptr = ((char*)ptr) + page_size - MAGIC_SIZE_TO_REAL(0);
+        }
+        else {
+            ptr = NULL;
+        }
+        if (flags & MAP_SHARED)
+            dsentry_flags |= MAGIC_STATE_SHM;
+        data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, dsentry_flags);
+        if(data_ptr == MAGIC_MEM_FAILED) {
+            munmap(aligned_ptr, page_size+length);
+            data_ptr = NULL;
+            errno = ENOMEM;
+        }
+        if(!data_ptr) {
+            errno = ENOMEM;
+            data_ptr = MAP_FAILED;
+        } else {
+            MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = flags;
+            MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = prot;
+        }
+    }
+    else {
+        data_ptr = MAP_FAILED;
+        errno = EINVAL;
+    }
+
+    MAGIC_MEM_WRAPPER_END();
+
+    return data_ptr;
+}
+
+#else
+/*===========================================================================*
+ *                               magic_vm_map_cacheblock                                *
+ *===========================================================================*/
+PUBLIC void *magic_vm_map_cacheblock(__MA_ARGS__ dev_t dev, off_t dev_offset,
+    ino_t ino, off_t ino_offset, u32_t *flags, int length)
+{
+    void *ptr, *data_ptr, *aligned_ptr;
+    int dsentry_flags = MAGIC_STATE_MAP;
+    size_t alloc_length;
+    size_t page_size = MAGIC_PAGE_SIZE;
+
+    MAGIC_MEM_WRAPPER_BEGIN();
+
+    if(length > 0) {
+        assert(MAGIC_SIZE_TO_REAL(length) <= page_size+length);
+        alloc_length = length + (length % page_size == 0 ? 0 : page_size-(length % page_size));
+        data_ptr = vm_map_cacheblock(dev, dev_offset, ino, ino_offset, flags, length);
+        if (data_ptr != MAP_FAILED) {
+            ptr = mmap(data_ptr-page_size, page_size, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+            MAGIC_MEM_PRINTF("vm_map_cacheblock: ptr = mmap(start, length, prot, flags, fd, offset) <-> 0x%08x = mmap(0x%08x, %d, 0x%08x, 0x%08x, %d, %d)\n", (unsigned) ptr, data_ptr-page_size, page_size, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+            assert(ptr == data_ptr-page_size); /* Ensured by VM. */
+            aligned_ptr = ptr;
+            ptr = ((char*)ptr) + page_size - MAGIC_SIZE_TO_REAL(0);
+        }
+        else {
+            aligned_ptr = NULL;
+            ptr = NULL;
+        }
+        data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, dsentry_flags);
+        if(data_ptr == MAGIC_MEM_FAILED) {
+            munmap(aligned_ptr, page_size+length);
+            data_ptr = NULL;
+        }
+        if(!data_ptr) {
+            data_ptr = MAP_FAILED;
+            errno = ENOMEM;
+        } else {
+            MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE;
+            MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = magic_mmap_dsentry_header_prot;
+        }
+    }
+    else {
+        data_ptr = MAP_FAILED;
+        errno = EINVAL;
+    }
+
+    MAGIC_MEM_WRAPPER_END();
+
+    return data_ptr;
+}
+#endif
+
diff --git a/minix/llvm/static/magic/magic_range.c b/minix/llvm/static/magic/magic_range.c
new file mode 100644 (file)
index 0000000..f65f59a
--- /dev/null
@@ -0,0 +1,321 @@
+#define MAGIC_RANGE_DEBUG                   MAGIC_DEBUG_SET(0)
+
+#include <magic_range.h>
+
+/*===========================================================================*
+ *                           magic_range_is_shlib                            *
+ *===========================================================================*/
+PRIVATE int magic_range_is_shlib(void *addr, void **container)
+{
+    /*
+     * NB!: This function requires the calling thread to already
+     * hold the DSODESC lock.
+     */
+    int ret = 0;
+    struct _magic_sodesc *sodesc;
+    struct _magic_dsodesc *dsodesc;
+
+    /* First iterate through the SO descriptors. */
+    MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc,
+        /* First check the text range. */
+        MAGIC_RANGE_DEBUG_ADDR(addr, sodesc->lib.text_range);
+        if (MAGIC_ADDR_IS_IN_RANGE(addr, sodesc->lib.text_range)) {
+            ret |= MAGIC_STATE_TEXT;
+            goto found_so;
+        }
+        /* Next check the data range. */
+        MAGIC_RANGE_DEBUG_ADDR(addr, sodesc->lib.data_range);
+        if (MAGIC_ADDR_IS_IN_RANGE(addr, sodesc->lib.data_range)) {
+            ret |= MAGIC_STATE_DATA;
+            goto found_so;
+        }
+    );
+
+    /* Next iterate through the DSO descriptors. */
+    MAGIC_SODESC_ITER(_magic_first_dsodesc, dsodesc,
+        /* First check the text range. */
+        MAGIC_RANGE_DEBUG_ADDR(addr, dsodesc->lib.text_range);
+        if (MAGIC_ADDR_IS_IN_RANGE(addr, dsodesc->lib.text_range)) {
+            ret |= MAGIC_STATE_TEXT;
+            goto found_dso;
+        }
+        /* Next check the data range. */
+        MAGIC_RANGE_DEBUG_ADDR(addr, dsodesc->lib.data_range);
+        if (MAGIC_ADDR_IS_IN_RANGE(addr, dsodesc->lib.data_range)) {
+            ret |= MAGIC_STATE_DATA;
+            goto found_dso;
+        }
+    );
+
+
+out:
+    return ret;
+found_so:
+    ret |= MAGIC_STATE_LIB | MAGIC_STATE_LIB_SO;
+    if (container != NULL)
+        *container = (void *)(sodesc);
+    goto out;
+found_dso:
+    ret |= MAGIC_STATE_LIB | MAGIC_STATE_LIB_DSO;
+    if (container != NULL) {
+        *container = (void *)(dsodesc);
+    }
+    goto out;
+
+}
+
+/*===========================================================================*
+ *                          magic_range_is_data                              *
+ *===========================================================================*/
+PRIVATE INLINE int magic_range_is_data(void *addr)
+{
+    MAGIC_RANGE_DEBUG_ADDR(addr, magic_data_range);
+    return MAGIC_ADDR_IS_IN_RANGE(addr, magic_data_range) ? MAGIC_STATE_DATA : 0;
+}
+
+/*===========================================================================*
+ *                          magic_range_is_text                              *
+ *===========================================================================*/
+PRIVATE INLINE int magic_range_is_text(void *addr)
+{
+    MAGIC_RANGE_DEBUG_ADDR(addr, magic_text_range);
+    return MAGIC_ADDR_IS_IN_RANGE(addr, magic_text_range) ? MAGIC_STATE_TEXT : 0;
+}
+
+/*===========================================================================*
+ *                          magic_range_is_heap                              *
+ *===========================================================================*/
+PRIVATE INLINE int magic_range_is_heap(void *addr)
+{
+    void* heap_range[2];
+    MAGIC_RANGE_SET_MIN(heap_range, magic_heap_start);
+    MAGIC_RANGE_SET_MAX(heap_range, (char *)magic_heap_end + MAGIC_HEAP_GAP);
+    MAGIC_RANGE_DEBUG_ADDR(addr, heap_range);
+    return MAGIC_ADDR_IS_IN_RANGE(addr, heap_range) ? MAGIC_STATE_HEAP : 0;
+}
+
+/*===========================================================================*
+ *                          magic_range_is_stack                             *
+ *===========================================================================*/
+PUBLIC int magic_range_is_stack(void *addr)
+{
+    /*
+     * NB!: This function requires the calling thread to already
+     * hold the DSENTRY lock.
+     */
+    struct _magic_sentry *sentry;
+    int ret;
+    void *stack_range[2];
+
+    MAGIC_RANGE_INIT(stack_range);
+    assert(_magic_first_stack_dsentry && _magic_last_stack_dsentry);
+    sentry = MAGIC_DSENTRY_TO_SENTRY(_magic_first_stack_dsentry);
+    MAGIC_RANGE_SET_MIN(stack_range,
+        (char *) MAGIC_DSENTRY_TO_SENTRY(_magic_last_stack_dsentry)->address -
+        MAGIC_STACK_GAP);
+    MAGIC_RANGE_SET_MAX(stack_range,
+        ((char *) sentry->address) + sentry->type->size - 1);
+#if MAGIC_RANGE_ROUND_STACK
+    MAGIC_RANGE_PAGE_ROUND(stack_range);
+#endif
+    MAGIC_RANGE_DEBUG_ADDR(addr, stack_range);
+    ret = MAGIC_ADDR_IS_IN_RANGE(addr, stack_range) ? MAGIC_STATE_STACK : 0;
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                         magic_range_is_dsentry                            *
+ *===========================================================================*/
+PUBLIC int magic_range_is_dsentry(void *addr)
+{
+    /*
+     * NB!: This function requires the calling thread to already
+     * hold the DSENTRY lock.
+     */
+    int ret = 0;
+    void *start_address, *end_address;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry *sentry;
+    int region;
+
+    if(magic_update_dsentry_ranges) {
+        MAGIC_RANGE_INIT(magic_heap_range);
+        MAGIC_RANGE_INIT(magic_map_range);
+        MAGIC_RANGE_INIT(magic_shm_range);
+        MAGIC_RANGE_INIT(magic_stack_range);
+        MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+            start_address = sentry->address;
+            end_address = (void *) (((char *)sentry->address) +
+                sentry->type->size - 1);
+            region = MAGIC_STATE_REGION(sentry);
+            if(region & MAGIC_STATE_HEAP) {
+                MAGIC_RANGE_UPDATE(magic_heap_range, start_address, end_address);
+            }
+            else if(region & MAGIC_STATE_MAP) {
+                MAGIC_RANGE_UPDATE(magic_map_range, start_address, end_address);
+            }
+            else if(region & MAGIC_STATE_SHM) {
+                MAGIC_RANGE_UPDATE(magic_shm_range, start_address, end_address);
+            }
+            else if(region & MAGIC_STATE_STACK) {
+                MAGIC_RANGE_UPDATE(magic_stack_range, start_address, end_address);
+            }
+        );
+        magic_update_dsentry_ranges = 0;
+    }
+    MAGIC_RANGE_DEBUG_ADDR(addr, magic_heap_range);
+    if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_heap_range)) {
+        ret |= MAGIC_STATE_HEAP;
+    }
+    MAGIC_RANGE_DEBUG_ADDR(addr, magic_map_range);
+    if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_map_range)) {
+        ret |= MAGIC_STATE_MAP;
+    }
+    MAGIC_RANGE_DEBUG_ADDR(addr, magic_shm_range);
+    if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_shm_range)) {
+        ret |= MAGIC_STATE_SHM;
+    }
+    MAGIC_RANGE_DEBUG_ADDR(addr, magic_stack_range);
+    if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_stack_range)) {
+        ret |= MAGIC_STATE_STACK;
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                        magic_range_is_dfunction                           *
+ *===========================================================================*/
+PUBLIC int magic_range_is_dfunction(void *addr)
+{
+    /*
+     * NB!: This function requires the calling thread to already
+     * hold the DFUNCTION lock.
+     */
+    int ret = 0;
+    void *start_address;
+    struct _magic_dfunction* dfunction;
+    struct _magic_function* function;
+    int region;
+
+    if(magic_update_dfunction_ranges) {
+        MAGIC_RANGE_INIT(magic_dfunction_range);
+        MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
+            start_address = function->address;
+            region = MAGIC_STATE_REGION(function);
+            assert(region & MAGIC_STATE_TEXT);
+            MAGIC_RANGE_UPDATE(magic_dfunction_range, start_address, start_address);
+        );
+        magic_update_dfunction_ranges = 0;
+    }
+    MAGIC_RANGE_DEBUG_ADDR(addr, magic_dfunction_range);
+    if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_dfunction_range)) {
+        ret |= MAGIC_STATE_TEXT;
+    }
+
+    return ret;
+}
+
+/*===========================================================================*
+ *                           magic_ranges_init                               *
+ *===========================================================================*/
+PUBLIC void magic_ranges_init(void)
+{
+    int i,j;
+    void *start_address, *end_address;
+    void* linker_vars[] = { MAGIC_LINKER_VAR_NAMES };
+
+    /* Init sentry and data range. */
+    MAGIC_RANGE_INIT(magic_data_range);
+    MAGIC_RANGE_INIT(magic_sentry_range);
+    for (i = 0 ; i < _magic_sentries_num ; i++) {
+        start_address = _magic_sentries[i].address;
+        end_address = (void *) (((char *)_magic_sentries[i].address)+_magic_sentries[i].type->size-1);
+        MAGIC_RANGE_UPDATE(magic_sentry_range, start_address, end_address);
+        j = 0;
+        while (linker_vars[j] && strcmp(linker_vars[j], _magic_sentries[i].name)) j++;
+        if (linker_vars[j] || MAGIC_STATE_FLAG(&_magic_sentries[i], MAGIC_STATE_THREAD_LOCAL)
+            || MAGIC_STATE_FLAG(&_magic_sentries[i], MAGIC_STATE_EXTERNAL)) {
+            continue;
+        }
+        MAGIC_RANGE_UPDATE(magic_data_range, start_address, end_address);
+    }
+#if MAGIC_RANGE_ROUND_DATA
+    MAGIC_RANGE_PAGE_ROUND(magic_data_range);
+#endif
+
+    /* Init function range. */
+    MAGIC_RANGE_INIT(magic_function_range);
+    for (i = 0 ; i < _magic_functions_num ; i++) {
+        start_address = _magic_functions[i].address;
+        MAGIC_RANGE_UPDATE(magic_function_range, start_address, start_address);
+    }
+
+    /* Init text range. */
+#ifdef __MINIX
+    MAGIC_RANGE_SET(magic_text_range, MAGIC_TEXT_START,
+        MAGIC_TEXT_END ? MAGIC_TEXT_END : ((char *)magic_function_range[1]));
+#else
+    MAGIC_RANGE_SET(magic_text_range, MAGIC_TEXT_START,
+        MAGIC_TEXT_END ? MAGIC_TEXT_END : ((char *)magic_data_range[0] - 1));
+#endif
+#if MAGIC_RANGE_ROUND_TEXT
+    MAGIC_RANGE_PAGE_ROUND(magic_text_range);
+#endif
+
+    /* Init heap start. */
+    magic_heap_start = MAGIC_HEAP_START ? MAGIC_HEAP_START : ((char *)magic_data_range[1] + 1);
+    magic_heap_end = ((char *)sbrk(0)) - 1;
+
+    /* Defaults for other ranges. */
+    MAGIC_RANGE_INIT(magic_heap_range);
+    MAGIC_RANGE_INIT(magic_map_range);
+    MAGIC_RANGE_INIT(magic_shm_range);
+    MAGIC_RANGE_INIT(magic_stack_range);
+    MAGIC_RANGE_INIT(magic_dfunction_range);
+}
+
+/*===========================================================================*
+ *                        magic_range_lookup_by_addr                         *
+ *===========================================================================*/
+PUBLIC int magic_range_lookup_by_addr(void *addr, void **container)
+{
+    /*
+     * NB!: This function requires the calling thread to already
+     * hold the DSENTRY, DFUNCTION and DSODESC locks.
+     */
+    int ret;
+    /* Constant ranges first. */
+    if (magic_range_is_data(addr)) {
+        return MAGIC_STATE_DATA;
+    }
+    if (magic_range_is_text(addr)) {
+        return MAGIC_STATE_TEXT;
+    }
+
+    /* Non-dsentry ranges next. */
+    if (magic_range_is_heap(addr)) {
+        return MAGIC_STATE_HEAP;
+    }
+    if (magic_range_is_stack(addr)) {
+        return MAGIC_STATE_STACK;
+    }
+
+    /* Shared library ranges. */
+#if 0
+    /* XXX: This kind of range isn't very accurate. */
+    if (magic_range_is_dfunction(addr)) {
+        return MAGIC_STATE_LIB | MAGIC_STATE_TEXT;
+    }
+#endif
+
+    if ((ret = magic_range_is_shlib(addr, container))) {
+        return ret;
+    }
+
+    /* Dsentry ranges last. */
+    return magic_range_is_dsentry(addr);
+}
+
+
diff --git a/minix/llvm/static/magic/magic_selement.c b/minix/llvm/static/magic/magic_selement.c
new file mode 100644 (file)
index 0000000..8588715
--- /dev/null
@@ -0,0 +1,935 @@
+#include <magic_selement.h>
+
+/*===========================================================================*
+ *                      magic_selement_lookup_by_name                        *
+ *===========================================================================*/
+PUBLIC int magic_selement_lookup_by_name(char *name,
+    _magic_selement_t *selement, struct _magic_dsentry *dsentry_buff)
+{
+    char token_buff[MAGIC_MAX_NAME_LEN * 2 + 2];
+    char *token_start = name;
+    int last_num_seps = 0;
+    char *s;
+    if (!name || *name == '\0' || *name == MAGIC_SELEMENT_SEP[0]) {
+        return MAGIC_ENOENT;
+    }
+    for (s = name; *s; s++) {
+        if (*(s + 1) == '\0' || *(s + 1) == MAGIC_SELEMENT_SEP[0]) {
+            size_t len = s - token_start + 1;
+            if (len >= MAGIC_MAX_NAME_LEN * 2 + 1) {
+                return MAGIC_ENOMEM;
+            }
+            strncpy(token_buff, token_start, len);
+            token_buff[len] = '\0';
+            if (token_start == name) {
+                struct _magic_sentry *sentry;
+                char *sentry_parent_name = "", *sentry_name = NULL;
+                char *delim = NULL;
+                _magic_id_t dsentry_site_id = MAGIC_DSENTRY_SITE_ID_NULL;
+                if (!(delim = strchr(token_buff, MAGIC_DSENTRY_ABS_NAME_SEP[0]))) {
+                    /* Regular sentry, no parent name or site_id. */
+                    sentry_name = token_buff;
+                } else {
+                    /*
+                     * Dsentry. Will contain: sentry_id<DELIM>parent_name<DELIM>name<DELIM>site_id.
+                     */
+                    delim = '\0';
+                    /* Skip sentry_id */
+                    sentry_parent_name = delim + 1;
+                    delim = strchr(delim + 1, MAGIC_DSENTRY_ABS_NAME_SEP[0]);
+                    assert(!delim && "No dsentry name found in selement name!");
+                    delim = '\0';
+                    sentry_name = delim + 1;
+                    delim = strchr(delim + 1, MAGIC_DSENTRY_ABS_NAME_SEP[0]);
+                    assert(!delim && "No dsentry site id found in selement name!");
+                    delim = '\0';
+                    dsentry_site_id = strtoul((const char*)delim+1, NULL, 10);
+                }
+
+                sentry = magic_sentry_lookup_by_name(sentry_parent_name, sentry_name,
+                    dsentry_site_id, dsentry_buff);
+                if (!sentry) {
+                    return MAGIC_ENOENT;
+                }
+                magic_selement_from_sentry(sentry, selement);
+            }
+            else {
+                _magic_selement_t child_selement;
+                if (!magic_selement_from_relative_name(selement, &child_selement, token_buff)) {
+                    return MAGIC_ENOENT;
+                }
+                *selement = child_selement;
+            }
+            s++;
+            last_num_seps = 0;
+            while (*s == MAGIC_SELEMENT_SEP[0]) {
+                s++;
+                last_num_seps++;
+            }
+            token_start = s;
+            s--;
+        }
+    }
+    if (last_num_seps > 0 && selement->type->type_id == MAGIC_TYPE_POINTER) {
+        int steps = magic_selement_recurse_ptr(selement, selement, last_num_seps);
+        if(steps != last_num_seps) {
+            return MAGIC_EINVAL;
+        }
+    }
+
+    return 0;
+}
+
+/*===========================================================================*
+ *                       magic_selement_name_print_cb                        *
+ *===========================================================================*/
+PUBLIC int magic_selement_name_print_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num,
+    const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
+{
+    _magic_selement_t *selement = (_magic_selement_t*) cb_args;
+    struct _magic_sentry* sentry = selement->sentry;
+    void *address = (char*)sentry->address + offset;
+    void *range[2];
+    MAGIC_RANGE_SET_MIN(range, address);
+    MAGIC_RANGE_SET_MAX(range, (char*) address + type->size-1);
+    if(!MAGIC_ADDR_IS_IN_RANGE(selement->address, range)) {
+        return MAGIC_TYPE_WALK_SKIP_PATH;
+    }
+    if(address == sentry->address && type == sentry->type) {
+        magic_print_sentry_abs_name(sentry);
+    }
+    else {
+        short is_parent_array = parent_type->type_id == MAGIC_TYPE_ARRAY || parent_type->type_id == MAGIC_TYPE_VECTOR;
+        if(is_parent_array) {
+            _magic_printf("%s%d", MAGIC_SELEMENT_SEP, child_num);
+        }
+        else {
+            _magic_printf("%s%s", MAGIC_SELEMENT_SEP, parent_type->member_names[child_num]);
+        }
+    }
+    if(type->num_child_types == 0
+        || (address == selement->address && type == selement->type)) {
+        return MAGIC_TYPE_WALK_STOP;
+    }
+    return MAGIC_TYPE_WALK_CONTINUE;
+}
+
+/*===========================================================================*
+ *                       magic_selement_name_get_cb                          *
+ *===========================================================================*/
+PUBLIC int magic_selement_name_get_cb(const struct _magic_type *parent_type,
+    const unsigned parent_offset, int child_num, const struct _magic_type *type,
+    const unsigned offset, int depth, void *args_array)
+{
+    void **cb_args = (void **) args_array;
+
+    _magic_selement_t *selement = (_magic_selement_t*) cb_args[0];
+    char **buf = (char **) cb_args + 1;
+    int count, *buf_size = (int *) cb_args + 2;
+
+    short is_array = type->type_id == MAGIC_TYPE_ARRAY || type->type_id == MAGIC_TYPE_VECTOR;
+
+    struct _magic_sentry *sentry = selement->sentry;
+    void *address = (char *)sentry->address + offset;
+    void *range[2];
+    MAGIC_RANGE_SET_MIN(range, address);
+    MAGIC_RANGE_SET_MAX(range, (char *) address + type->size - 1);
+    if (!MAGIC_ADDR_IS_IN_RANGE(selement->address, range)) {
+        return MAGIC_TYPE_WALK_SKIP_PATH;
+    }
+
+    if (address == sentry->address && type == sentry->type) {
+        if (!(sentry->flags & MAGIC_STATE_DYNAMIC)) {
+            count = snprintf(*buf, *buf_size, "%s", sentry->name);
+            if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP;    /* Buffer too small. */
+            *buf += count;
+            *buf_size -= count;
+        } else {
+            struct _magic_dsentry *dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
+            assert(dsentry->parent_name && strcmp(dsentry->parent_name, ""));
+            assert(sentry->name && strcmp(sentry->name, ""));
+            count = snprintf(*buf, *buf_size, "%lu%s%s%s%s%s" MAGIC_ID_FORMAT,
+                (unsigned long)MAGIC_SENTRY_ID(sentry), MAGIC_DSENTRY_ABS_NAME_SEP,
+                dsentry->parent_name, MAGIC_DSENTRY_ABS_NAME_SEP, sentry->name,
+                MAGIC_DSENTRY_ABS_NAME_SEP, dsentry->site_id);
+            if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP;    /* Buffer too small. */
+            *buf += count;
+            *buf_size -= count;
+        }
+    } else {
+        short is_parent_array = parent_type->type_id == MAGIC_TYPE_ARRAY ||
+            parent_type->type_id == MAGIC_TYPE_VECTOR;
+        if (is_parent_array) {
+            count = snprintf(*buf, *buf_size, "%s%d",
+                MAGIC_SELEMENT_SEP, child_num);
+            if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP;    /* Buffer too small. */
+            *buf += count;
+            *buf_size -= count;
+        } else {
+            count = snprintf(*buf, *buf_size, "%s%s",
+                MAGIC_SELEMENT_SEP, parent_type->member_names[child_num]);
+            if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP;    /* Buffer too small. */
+            *buf += count;
+            *buf_size -= count;
+        }
+    }
+
+    if (type->num_child_types == 0
+    || (address == selement->address && type == selement->type)
+    || (is_array && address == selement->address && type == selement->parent_type)) {
+        return MAGIC_TYPE_WALK_STOP;
+    }
+
+    return MAGIC_TYPE_WALK_CONTINUE;
+}
+
+/*===========================================================================*
+ *                        magic_selement_print_value                         *
+ *===========================================================================*/
+PUBLIC void magic_selement_print_value(const _magic_selement_t *selement)
+{
+    int type_id = selement->type->type_id;
+    unsigned size = selement->type->size;
+    double dvalue;
+    void *pvalue;
+    unsigned long uvalue;
+    long ivalue;
+    char vvalue;
+    switch(type_id) {
+        case MAGIC_TYPE_FLOAT:
+            dvalue = magic_selement_to_float(selement);
+            _magic_printf("float(%d):%g", size, dvalue);
+            _magic_printf("/%d", (long) dvalue);
+        break;
+
+        case MAGIC_TYPE_POINTER:
+            pvalue = magic_selement_to_ptr(selement);
+            _magic_printf("ptr:%08x", pvalue);
+        break;
+
+        case MAGIC_TYPE_INTEGER:
+        case MAGIC_TYPE_ENUM:
+            if(MAGIC_TYPE_FLAG(selement->type, MAGIC_TYPE_UNSIGNED)) {
+                uvalue = magic_selement_to_unsigned(selement);
+                _magic_printf("unsigned %s(%d):%u", type_id == MAGIC_TYPE_INTEGER ? "int" : "enum", size, uvalue);
+            }
+            else {
+                ivalue = magic_selement_to_int(selement);
+                _magic_printf("%s(%d):%d", type_id == MAGIC_TYPE_INTEGER ? "int" : "enum", size, ivalue);
+            }
+        break;
+
+        case MAGIC_TYPE_VOID:
+            vvalue = *((char*) selement->address);
+            _magic_printf("void(%d):%d", size, vvalue);
+        break;
+
+        default:
+            _magic_printf("???");
+        break;
+    }
+}
+
+/*===========================================================================*
+ *                         magic_selement_to_unsigned                        *
+ *===========================================================================*/
+PUBLIC unsigned long magic_selement_to_unsigned(const _magic_selement_t *selement)
+{
+    void *address = selement->address;
+    const struct _magic_type* type = selement->type;
+    unsigned long value = 0;
+    unsigned size = type->size;
+    assert(size > 0);
+    assert(type->type_id == MAGIC_TYPE_INTEGER
+        || type->type_id == MAGIC_TYPE_ENUM);
+
+    if(address == NULL)
+       return 0;
+
+    if(size == sizeof(unsigned char)) {
+        value = (unsigned long) *((unsigned char*) address);
+    }
+    else if(size == sizeof(unsigned short)) {
+        value = (unsigned long) *((unsigned short*) address);
+    }
+#ifdef MAGIC_LONG_LONG_SUPPORTED
+    else if(size == sizeof(unsigned long long)) {
+        value = (unsigned long) *((unsigned long long*) address);
+    }
+#endif
+    else {
+        assert(size == sizeof(unsigned long));
+        value = *((unsigned long*) address);
+    }
+
+    return value;
+}
+
+/*===========================================================================*
+ *                           magic_selement_to_int                           *
+ *===========================================================================*/
+PUBLIC long magic_selement_to_int(const _magic_selement_t *selement)
+{
+    void *address = selement->address;
+    const struct _magic_type* type = selement->type;
+    long value = 0;
+    unsigned size = type->size;
+    assert(size > 0);
+    assert(type->type_id == MAGIC_TYPE_INTEGER
+        || type->type_id == MAGIC_TYPE_ENUM);
+
+    if(address == NULL)
+       return 0;
+
+    if(size == sizeof(char)) {
+        value = (long) *((char*) address);
+    }
+    else if(size == sizeof(short)) {
+        value = (long) *((short*) address);
+    }
+#ifdef MAGIC_LONG_LONG_SUPPORTED
+    else if(size == sizeof(long long)) {
+        value = (long) *((long long*) address);
+    }
+#endif
+    else {
+        assert(size == sizeof(long));
+        value = *((long*) address);
+    }
+
+    return value;
+}
+
+#ifdef MAGIC_LONG_LONG_SUPPORTED
+/*===========================================================================*
+ *                            magic_selement_to_llu                          *
+ *===========================================================================*/
+PUBLIC unsigned long long magic_selement_to_llu(const _magic_selement_t *selement)
+{
+    void *address = selement->address;
+    const struct _magic_type* type = selement->type;
+    unsigned long long value;
+    unsigned size = type->size;
+
+    if(address == NULL)
+       return 0;
+
+    if (size == sizeof(unsigned long long))
+        value = *((unsigned long long*) address);
+    else
+        value = (unsigned long long) magic_selement_to_unsigned(selement);
+    return value;
+}
+
+/*===========================================================================*
+ *                            magic_selement_to_ll                           *
+ *===========================================================================*/
+PUBLIC long long magic_selement_to_ll(const _magic_selement_t *selement)
+{
+    void *address = selement->address;
+    const struct _magic_type* type = selement->type;
+    long long value;
+    unsigned size = type->size;
+
+    if(address == NULL)
+       return 0;
+
+    if (size == sizeof(long long))
+        value = *((long long*) address);
+    else
+        value = (long long) magic_selement_to_int(selement);
+    return value;
+}
+#endif
+
+/*===========================================================================*
+ *                          magic_selement_to_float                          *
+ *===========================================================================*/
+PUBLIC double magic_selement_to_float(const _magic_selement_t *selement)
+{
+    void *address = selement->address;
+    const struct _magic_type* type = selement->type;
+    double value = 0.0;
+    unsigned size = type->size;
+    assert(size > 0);
+    assert(type->type_id == MAGIC_TYPE_FLOAT);
+
+    if(address == NULL)
+       return 0;
+
+    if(size == sizeof(float)) {
+        value = (double) *((float*) address);
+    }
+#ifdef MAGIC_LONG_DOUBLE_SUPPORTED
+    else if(size == sizeof(long double)) {
+        value = (double) *((long double*) address);
+    }
+#endif
+    else {
+        assert(size == sizeof(double));
+        value = *((double*) address);
+    }
+
+    return value;
+}
+
+/*===========================================================================*
+ *                           magic_selement_to_ptr                           *
+ *===========================================================================*/
+PUBLIC void* magic_selement_to_ptr(const _magic_selement_t *selement)
+{
+    void *address = selement->address;
+    const struct _magic_type* type = selement->type;
+    void* value = NULL;
+    assert(type->type_id == MAGIC_TYPE_POINTER);
+
+    if (!address)
+        return NULL;
+    value = *((void**) address);
+    return value;
+}
+
+/*===========================================================================*
+ *                         magic_selement_from_unsigned                      *
+ *===========================================================================*/
+PUBLIC void magic_selement_from_unsigned(const _magic_selement_t *selement, unsigned long value)
+{
+    void *address = selement->address;
+    const struct _magic_type* type = selement->type;
+    unsigned size = type->size;
+    assert(size > 0);
+    assert(type->type_id == MAGIC_TYPE_INTEGER
+        || type->type_id == MAGIC_TYPE_ENUM);
+
+    /* Prevent a store to NULL. */
+    if(address == NULL)
+       return;
+
+    if(size == sizeof(unsigned char)) {
+        *((unsigned char*) address) = (unsigned char) value;
+    }
+    else if(size == sizeof(unsigned short)) {
+        *((unsigned short*) address) = (unsigned short) value;
+    }
+#ifdef MAGIC_LONG_LONG_SUPPORTED
+    else if(size == sizeof(unsigned long long)) {
+        *((unsigned long long*) address) = (unsigned long long) value;
+    }
+#endif
+    else {
+        assert(size == sizeof(unsigned long));
+        *((unsigned long*) address) = (unsigned long) value;
+    }
+}
+
+/*===========================================================================*
+ *                           magic_selement_from_int                         *
+ *===========================================================================*/
+PUBLIC void magic_selement_from_int(const _magic_selement_t *selement, long value)
+{
+    void *address = selement->address;
+    const struct _magic_type* type = selement->type;
+    unsigned size = type->size;
+    assert(size > 0);
+    assert(type->type_id == MAGIC_TYPE_INTEGER
+        || type->type_id == MAGIC_TYPE_ENUM);
+
+    /* Prevent a store to NULL. */
+    if(address == NULL)
+       return;
+
+    if(size == sizeof(char)) {
+        *((char*) address) = (char) value;
+    }
+    else if(size == sizeof(short)) {
+        *((short*) address) = (short) value;
+    }
+#ifdef MAGIC_LONG_LONG_SUPPORTED
+    else if(size == sizeof(long long)) {
+        *((long long*) address) = (long long) value;
+    }
+#endif
+    else {
+        assert(size == sizeof(long));
+        *((long*) address) = (long) value;
+    }
+}
+
+/*===========================================================================*
+ *                          magic_selement_from_float                        *
+ *===========================================================================*/
+PUBLIC void magic_selement_from_float(const _magic_selement_t *selement, double value)
+{
+    void *address = selement->address;
+    const struct _magic_type* type = selement->type;
+    unsigned size = type->size;
+    assert(size > 0);
+    assert(type->type_id == MAGIC_TYPE_FLOAT);
+
+    /* Prevent a store to NULL. */
+    if(address == NULL)
+       return;
+
+    if(size == sizeof(float)) {
+        *((float*) address) = (float) value;
+    }
+#ifdef MAGIC_LONG_DOUBLE_SUPPORTED
+    else if(size == sizeof(long double)) {
+        *((long double*) address) = (long double) value;
+    }
+#endif
+    else {
+        assert(size == sizeof(double));
+        *((double*) address) = (double) value;
+    }
+}
+
+/*===========================================================================*
+ *                      magic_selement_ptr_value_cast                        *
+ *===========================================================================*/
+PUBLIC int magic_selement_ptr_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
+{
+    int src_type_id = src_selement->type->type_id;
+    int dst_type_id = dst_selement->type->type_id;
+    unsigned src_size = src_selement->type->size;
+    unsigned dst_size = dst_selement->type->size;
+    void* src_value;
+    int r = 0;
+    assert(dst_size > 0);
+
+    if(dst_type_id != MAGIC_TYPE_POINTER) {
+        return EINVAL;
+    }
+    assert(dst_size == sizeof(void*));
+    if(src_size != sizeof(void*)) {
+        return EINVAL;
+    }
+    switch(src_type_id) {
+        case MAGIC_TYPE_POINTER:
+            return 0;
+        break;
+
+        case MAGIC_TYPE_INTEGER:
+            if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
+                MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, void*, &r, 0);
+                assert(r == 0);
+            }
+            else {
+                MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, void*, &r, 0);
+                assert(r == 0);
+            }
+        break;
+
+        default:
+            return EINVAL;
+        break;
+    }
+
+    MAGIC_CHECKED_VALUE_DST_CAST(src_value, void*, value_buffer, void*, &r);
+    assert(r == 0);
+
+    return dst_size;
+}
+
+/*===========================================================================*
+ *                    magic_selement_unsigned_value_cast                     *
+ *===========================================================================*/
+PUBLIC int magic_selement_unsigned_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
+{
+    int src_type_id = src_selement->type->type_id;
+    int dst_type_id = dst_selement->type->type_id;
+    int r = 0;
+    unsigned src_size = src_selement->type->size;
+    unsigned dst_size = dst_selement->type->size;
+    unsigned long src_value;
+    assert(dst_size > 0);
+
+    if(dst_type_id != MAGIC_TYPE_INTEGER && dst_type_id != MAGIC_TYPE_ENUM) {
+        return EINVAL;
+    }
+    switch(src_type_id) {
+        case MAGIC_TYPE_FLOAT:
+            MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_float(src_selement), double, src_value, unsigned long, &r, 1);
+        break;
+
+        case MAGIC_TYPE_POINTER:
+            if(dst_size != sizeof(void*)) {
+                return EINVAL;
+            }
+            MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_ptr(src_selement), void*, src_value, unsigned long, &r, 0);
+            assert(r == 0);
+        break;
+
+        case MAGIC_TYPE_INTEGER:
+        case MAGIC_TYPE_ENUM:
+            if(src_size == dst_size && MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED) == MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
+                return 0;
+            }
+            if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
+                MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, unsigned long, &r, 0);
+                assert(r == 0);
+            }
+            else {
+                MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, unsigned long, &r, 1);
+            }
+        break;
+
+        default:
+            return EINVAL;
+        break;
+    }
+
+    switch(dst_size) {
+        case sizeof(unsigned char):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned char, &r);
+        break;
+
+        case sizeof(unsigned short):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned short, &r);
+        break;
+
+        case sizeof(unsigned int):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned int, &r);
+        break;
+
+#ifdef MAGIC_LONG_LONG_SUPPORTED
+        case sizeof(unsigned long long):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned long long, &r);
+        break;
+#endif
+
+        default:
+            return EINVAL;
+        break;
+    }
+
+    if(r == 0) {
+        r = dst_size;
+    }
+
+    return r;
+}
+
+/*===========================================================================*
+ *                      magic_selement_int_value_cast                        *
+ *===========================================================================*/
+PUBLIC int magic_selement_int_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
+{
+    int src_type_id = src_selement->type->type_id;
+    int dst_type_id = dst_selement->type->type_id;
+    int r = 0;
+    unsigned src_size = src_selement->type->size;
+    unsigned dst_size = dst_selement->type->size;
+    long src_value;
+    assert(dst_size > 0);
+
+    if(dst_type_id != MAGIC_TYPE_INTEGER && dst_type_id != MAGIC_TYPE_ENUM) {
+        return EINVAL;
+    }
+
+    switch(src_type_id) {
+        case MAGIC_TYPE_FLOAT:
+            MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_float(src_selement), double, src_value, long, &r, 1);
+        break;
+
+        case MAGIC_TYPE_POINTER:
+            if(dst_size != sizeof(void*)) {
+                return EINVAL;
+            }
+            MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_ptr(src_selement), void*, src_value, long, &r, 0);
+            assert(r == 0);
+        break;
+
+        case MAGIC_TYPE_INTEGER:
+        case MAGIC_TYPE_ENUM:
+            if(src_size == dst_size && MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED) == MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
+                return 0;
+            }
+            if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
+                MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, long, &r, 1);
+            }
+            else {
+                MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, long, &r, 0);
+                assert(r == 0);
+            }
+        break;
+
+        default:
+            return EINVAL;
+        break;
+    }
+
+    switch(dst_size) {
+        case sizeof(char):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, char, &r);
+        break;
+
+        case sizeof(short):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, short, &r);
+        break;
+
+        case sizeof(int):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, int, &r);
+        break;
+
+#ifdef MAGIC_LONG_LONG_SUPPORTED
+        case sizeof(long long):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, long long, &r);
+        break;
+#endif
+
+        default:
+            return EINVAL;
+        break;
+    }
+
+    if(r == 0) {
+        r = dst_size;
+    }
+
+    return r;
+}
+
+/*===========================================================================*
+ *                      magic_selement_float_value_cast                      *
+ *===========================================================================*/
+PUBLIC int magic_selement_float_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
+{
+    int src_type_id = src_selement->type->type_id;
+    int dst_type_id = dst_selement->type->type_id;
+    int r = 0;
+    unsigned src_size = src_selement->type->size;
+    unsigned dst_size = dst_selement->type->size;
+    double src_value;
+    assert(dst_size > 0);
+
+    if(dst_type_id != MAGIC_TYPE_FLOAT) {
+        return EINVAL;
+    }
+    switch(src_type_id) {
+        case MAGIC_TYPE_FLOAT:
+            if(src_size == dst_size) {
+                return 0;
+            }
+            MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_float(src_selement), double, src_value, double, &r, 0);
+            assert(r == 0);
+        break;
+
+        case MAGIC_TYPE_INTEGER:
+        case MAGIC_TYPE_ENUM:
+            if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
+                MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, double, &r, 1);
+            }
+            else {
+                MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, double, &r, 1);
+            }
+        break;
+
+        default:
+            return EINVAL;
+        break;
+    }
+
+
+    switch(dst_size) {
+        case sizeof(float):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, double, value_buffer, float, &r);
+        break;
+
+        case sizeof(double):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, double, value_buffer, double, &r);
+        break;
+
+#ifdef MAGIC_LONG_DOUBLE_SUPPORTED
+        case sizeof(long double):
+            MAGIC_CHECKED_VALUE_DST_CAST(src_value, double, value_buffer, long double, &r);
+        break;
+#endif
+
+        default:
+            return EINVAL;
+        break;
+    }
+
+    if(r == 0) {
+        r = dst_size;
+    }
+
+    return r;
+}
+
+/*===========================================================================*
+ *                         magic_selement_value_cast                         *
+ *===========================================================================*/
+PUBLIC int magic_selement_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
+{
+    int r, src_type_id, dst_type_id;
+    size_t src_size, dst_size;
+    src_type_id = src_selement->type->type_id;
+    dst_type_id = dst_selement->type->type_id;
+    src_size = src_selement->type->size;
+    dst_size = dst_selement->type->size;
+    if(src_type_id == dst_type_id && src_size == dst_size && MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED) == MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
+        return 0;
+    }
+
+    /* No size change allowed in opaque value casts. */
+    if(src_type_id == MAGIC_TYPE_OPAQUE || dst_type_id == MAGIC_TYPE_OPAQUE) {
+        return src_size == dst_size ? 0 : EINVAL;
+    }
+
+    /* No size change allowed in void value casts. */
+    if(src_type_id == MAGIC_TYPE_VOID || dst_type_id == MAGIC_TYPE_VOID) {
+        return src_size == dst_size ? 0 : EINVAL;
+    }
+
+    switch(dst_type_id) {
+        case MAGIC_TYPE_POINTER:
+            /* Cast to pointer values. */
+            r = magic_selement_ptr_value_cast(src_selement, dst_selement, value_buffer);
+        break;
+
+        case MAGIC_TYPE_FLOAT:
+            /* Cast to float values. */
+            r = magic_selement_float_value_cast(src_selement, dst_selement, value_buffer);
+        break;
+
+        case MAGIC_TYPE_INTEGER:
+        case MAGIC_TYPE_ENUM:
+            if(MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
+                /* Cast to unsigned values. */
+                r = magic_selement_unsigned_value_cast(src_selement, dst_selement, value_buffer);
+            }
+            else {
+                /* Cast to integer values. */
+                r = magic_selement_int_value_cast(src_selement, dst_selement, value_buffer);
+            }
+        break;
+
+        default:
+            r = EINVAL;
+        break;
+    }
+    return r;
+}
+
+/*===========================================================================*
+ *                         magic_selement_get_parent                         *
+ *===========================================================================*/
+PUBLIC _magic_selement_t* magic_selement_get_parent(
+    const _magic_selement_t *selement, _magic_selement_t *parent_selement)
+{
+    if(!selement->parent_type) {
+        return NULL;
+    }
+
+    parent_selement->sentry = selement->sentry;
+    parent_selement->parent_type = NULL;
+    parent_selement->child_num = 0;
+    parent_selement->type = selement->parent_type;
+    parent_selement->address = selement->parent_address;
+    parent_selement->num = 0;
+    assert(parent_selement->address >= parent_selement->sentry->address);
+
+    return parent_selement;
+}
+
+/*===========================================================================*
+ *                    magic_selement_fill_from_parent_info                   *
+ *===========================================================================*/
+PUBLIC void magic_selement_fill_from_parent_info(_magic_selement_t *selement,
+    int walk_flags)
+{
+    unsigned offset;
+    magic_type_walk_step(selement->parent_type,
+        selement->child_num, &selement->type, &offset, walk_flags);
+    selement->address = (char*) selement->parent_address + offset;
+}
+
+/*===========================================================================*
+ *                         magic_selement_from_sentry                        *
+ *===========================================================================*/
+PUBLIC _magic_selement_t* magic_selement_from_sentry(struct _magic_sentry *sentry,
+    _magic_selement_t *selement)
+{
+    selement->sentry = sentry;
+    selement->parent_type = NULL;
+    selement->child_num = 0;
+    selement->type = sentry->type;
+    selement->address = sentry->address;
+    selement->num = 1;
+
+    return selement;
+}
+
+/*===========================================================================*
+ *                      magic_selement_from_relative_name                    *
+ *===========================================================================*/
+PUBLIC _magic_selement_t* magic_selement_from_relative_name(
+    _magic_selement_t *parent_selement, _magic_selement_t *selement, char* name)
+{
+    _magic_selement_t new_parent_selement;
+    const struct _magic_type* parent_type = parent_selement->type;
+    int parent_type_id = parent_type->type_id;
+    int walk_flags = 0;
+    int i, child_num = -1;
+    char *end;
+
+    if(!name || *name == '\0') {
+        return NULL;
+    }
+
+    if(parent_type_id == MAGIC_TYPE_UNION && (*name >= '0' && *name <= '9')) {
+        parent_type_id = MAGIC_TYPE_ARRAY;
+        walk_flags = MAGIC_TYPE_WALK_UNIONS_AS_VOID;
+    }
+
+    switch(parent_type_id) {
+        case MAGIC_TYPE_ARRAY:
+        case MAGIC_TYPE_VECTOR:
+            child_num = (int) strtol(name, &end, 10);
+            if(end == name || *end != '\0' || errno == ERANGE) {
+                return NULL;
+            }
+        break;
+
+        case MAGIC_TYPE_STRUCT:
+        case MAGIC_TYPE_UNION:
+            for(i=0;i<parent_type->num_child_types;i++) {
+                if(!strcmp(parent_type->member_names[i], name)) {
+                    child_num = i;
+                    break;
+                }
+            }
+            if(i == parent_type->num_child_types) {
+                return NULL;
+            }
+        break;
+
+        case MAGIC_TYPE_POINTER:
+            i = magic_selement_recurse_ptr(parent_selement, selement, MAGIC_SELEMENT_MAX_PTR_RECURSIONS);
+            if(i <= 0 || i >= MAGIC_SELEMENT_MAX_PTR_RECURSIONS) {
+                return NULL;
+            }
+            new_parent_selement = *selement;
+            return magic_selement_from_relative_name(&new_parent_selement, selement, name);
+        break;
+
+        default:
+            return NULL;
+        break;
+    }
+
+    if(child_num != -1) {
+        selement->sentry = parent_selement->sentry;
+        selement->parent_type = parent_type;
+        selement->parent_address = parent_selement->address;
+        selement->child_num = child_num;
+        selement->num = parent_selement->num+1;
+        magic_selement_fill_from_parent_info(selement, walk_flags);
+    }
+
+    return selement;
+}
+
diff --git a/minix/llvm/static/magic/magic_sentry.c b/minix/llvm/static/magic/magic_sentry.c
new file mode 100644 (file)
index 0000000..abf24ff
--- /dev/null
@@ -0,0 +1,919 @@
+#include <magic_sentry.h>
+#include <magic_splay_tree.h>
+
+/*===========================================================================*
+ *                         magic_sentry_get_off_by_n                         *
+ *===========================================================================*/
+PUBLIC long magic_sentry_get_off_by_n(struct _magic_sentry *sentry,
+    void *addr, int flags)
+{
+    char *el_addr = (char*) addr, *first_el_addr, *last_el_addr;
+    size_t el_size;
+    unsigned long n, diff;
+    long long_n;
+
+    if (sentry->type->type_id != MAGIC_TYPE_ARRAY) {
+        return LONG_MAX;
+    }
+    el_size = sentry->type->contained_types[0]->size;
+    first_el_addr = (char*) sentry->address;
+    last_el_addr = (first_el_addr+sentry->type->size-el_size);
+    if (el_addr >= last_el_addr) {
+        diff = (unsigned long) (el_addr - last_el_addr);
+    }
+    else if (el_addr <= first_el_addr) {
+        diff = (unsigned long) (first_el_addr - el_addr);
+    }
+    else {
+        return LONG_MAX;
+    }
+    if (diff % el_size != 0) {
+        return LONG_MAX;
+    }
+    n = diff / el_size;
+    if (n >= LONG_MAX) {
+        return LONG_MAX;
+    }
+    long_n = (el_addr >= last_el_addr ? (long) n : -((long)n));
+    if ((long_n < 0 && !(flags & MAGIC_SENTRY_OFF_BY_N_NEGATIVE))
+        || (long_n > 0 && !(flags & MAGIC_SENTRY_OFF_BY_N_POSITIVE))
+        || (long_n == 0 && !(flags & MAGIC_SENTRY_OFF_BY_N_ZERO))) {
+        return LONG_MAX;
+    }
+    return long_n;
+}
+
+/*===========================================================================*
+ *                           magic_do_check_sentry                           *
+ *===========================================================================*/
+PRIVATE INLINE int magic_do_check_sentry(struct _magic_sentry *sentry)
+{
+    int is_size_ok;
+    assert(sentry && "NULL sentry found!");
+    is_size_ok = sentry->type->size > 0;
+    if (!is_size_ok) {
+        _magic_printf("magic_do_check_sentry: bad sentry, checks: %d\n", is_size_ok);
+        MAGIC_SENTRY_PRINT(sentry, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/*===========================================================================*
+ *                             magic_check_sentry                            *
+ *===========================================================================*/
+PUBLIC int magic_check_sentry(struct _magic_sentry *sentry)
+{
+    int check;
+    check = magic_do_check_sentry(sentry);
+    if (!check) {
+        return FALSE;
+    }
+
+#if MAGIC_CHECK_LEVEL == 2
+    check = magic_check_sentries();
+    if (!check) {
+        _magic_printf("magic_check_sentry: bad other sentry\n");
+        return FALSE;
+    }
+#endif
+
+    return TRUE;
+}
+
+/*===========================================================================*
+ *                          magic_check_sentries                             *
+ *===========================================================================*/
+PUBLIC int magic_check_sentries()
+{
+    int i, ret, check = TRUE;
+
+    for (i = 0 ; i < _magic_sentries_num ; i++) {
+        ret = magic_do_check_sentry(&_magic_sentries[i]);
+        if (ret == FALSE) {
+            check = FALSE;
+        }
+    }
+
+    return check;
+}
+
+/*===========================================================================*
+ *                         magic_sentry_lookup_by_id                         *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_id(_magic_id_t id,
+    struct _magic_dsentry *dsentry_buff)
+{
+    struct _magic_sentry *entry = NULL;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry *sentry;
+
+    if (id <= 0) {
+        return NULL;
+    }
+
+    /* O(1) ID lookup for sentries. */
+#if MAGIC_LOOKUP_SENTRY
+    if (id <= _magic_sentries_num) {
+        return &_magic_sentries[id - 1];
+    }
+#endif
+
+    /* O(N) ID lookup for dsentries. */
+#if MAGIC_LOOKUP_DSENTRY
+    MAGIC_DSENTRY_LOCK();
+    MAGIC_DSENTRY_ALIVE_NESTED_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+        if(sentry->id == id) {
+            if(dsentry_buff) {
+                magic_copy_dsentry(dsentry, dsentry_buff);
+                entry = MAGIC_DSENTRY_TO_SENTRY(dsentry_buff);
+            }
+            else {
+                entry = sentry;
+            }
+            break;
+        }
+    );
+    MAGIC_DSENTRY_UNLOCK();
+#endif
+
+    return entry;
+}
+
+/*===========================================================================*
+ *                        magic_sentry_lookup_by_addr                        *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_addr(void *addr,
+    struct _magic_dsentry *dsentry_buff)
+{
+    int i;
+    struct _magic_sentry *entry = NULL;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry *sentry;
+
+#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
+    if (magic_sentry_rl_index) {
+        sentry = magic_sentry_lookup_by_range_index(addr, dsentry_buff);
+        if (sentry && sentry->address == addr) {
+            return sentry;
+        } else {
+            return NULL;
+        }
+    }
+#endif
+
+    /* Scan all the entries and return the one matching the provided address. */
+#if MAGIC_LOOKUP_SENTRY
+    if (MAGIC_ADDR_IS_IN_RANGE(addr, magic_sentry_range)) {
+        for (i = 0 ; i < _magic_sentries_num ; i++) {
+            if (_magic_sentries[i].address == addr) {
+                entry = &_magic_sentries[i];
+                break;
+            }
+        }
+        if (entry) {
+            return entry;
+        }
+    }
+#endif
+
+#if MAGIC_LOOKUP_DSENTRY
+    MAGIC_DSENTRY_LOCK();
+    if (!MAGIC_ADDR_LOOKUP_USE_DSENTRY_RANGES || magic_range_is_dsentry(addr)) {
+        MAGIC_DSENTRY_ALIVE_BLOCK_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+            if (sentry->address == addr) {
+                if (dsentry_buff) {
+                    magic_copy_dsentry(dsentry, dsentry_buff);
+                    entry = MAGIC_DSENTRY_TO_SENTRY(dsentry_buff);
+                }
+                else {
+                    entry = sentry;
+                }
+                break;
+            }
+        );
+    }
+    MAGIC_DSENTRY_UNLOCK();
+#endif
+
+    return entry;
+}
+
+/*===========================================================================*
+ *                       magic_sentry_lookup_by_name                         *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_name(char *parent_name,
+    char *name, _magic_id_t site_id, struct _magic_dsentry *dsentry_buff)
+{
+    int i;
+    struct _magic_sentry *entry = NULL;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry *sentry;
+
+#if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH
+    if (magic_sentry_hash_head) {
+        return magic_sentry_lookup_by_name_hash(parent_name, name,
+            site_id, dsentry_buff);
+    }
+#endif
+
+    /* Scan all the entries and return the one matching the provided name. */
+#if MAGIC_LOOKUP_SENTRY
+    for (i = 0 ; i < _magic_sentries_num ; i++) {
+        if (!strcmp(_magic_sentries[i].name, name)) {
+            if (!parent_name ||
+                    !strcmp(MAGIC_SENTRY_PARENT(&_magic_sentries[i]),
+                    parent_name)) {
+                if (MAGIC_SENTRY_SITE_ID(&_magic_sentries[i]) == site_id) {
+                    entry = &_magic_sentries[i];
+                    break;
+                }
+            }
+        }
+    }
+    if (entry) {
+        return entry;
+    }
+#endif
+
+#if MAGIC_LOOKUP_DSENTRY
+    MAGIC_DSENTRY_LOCK();
+    MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry,
+        dsentry, sentry,
+        if (!strcmp(sentry->name, name)) {
+            if (!parent_name ||
+                    !strcmp(MAGIC_SENTRY_PARENT(sentry), parent_name)) {
+                if (site_id == MAGIC_DSENTRY_SITE_ID_NULL ||
+                        dsentry->site_id == site_id) {
+                    if (dsentry_buff) {
+                        magic_copy_dsentry(dsentry, dsentry_buff);
+                        entry = MAGIC_DSENTRY_TO_SENTRY(dsentry_buff);
+                    }
+                    else {
+                        entry = sentry;
+                    }
+                    break;
+                }
+            }
+        }
+    );
+    MAGIC_DSENTRY_UNLOCK();
+#endif
+
+    return entry;
+}
+
+/*===========================================================================*
+ *                        magic_sentry_lookup_by_range                       *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_range(void *addr,
+    struct _magic_dsentry *dsentry_buff)
+{
+    int i;
+    struct _magic_sentry *entry = NULL;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry *sentry;
+    void *start_address, *end_address;
+
+#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
+    if (magic_sentry_rl_index) {
+        return magic_sentry_lookup_by_range_index(addr, dsentry_buff);
+    }
+#endif
+
+    /* Scan all the entries and return the one with a valid range. */
+#if MAGIC_LOOKUP_SENTRY
+    if (MAGIC_ADDR_IS_IN_RANGE(addr, magic_sentry_range)) {
+        for (i = 0 ; i < _magic_sentries_num ; i++) {
+            start_address = _magic_sentries[i].address;
+            end_address = (void *) (((char *)_magic_sentries[i].address) +
+                _magic_sentries[i].type->size - 1);
+            if (MAGIC_ADDR_IS_WITHIN(addr, start_address, end_address)) {
+                entry = &_magic_sentries[i];
+                break;
+            }
+        }
+        if (entry) {
+            return entry;
+        }
+    }
+#endif
+
+#if MAGIC_LOOKUP_DSENTRY
+    MAGIC_DSENTRY_LOCK();
+    if (!MAGIC_ADDR_LOOKUP_USE_DSENTRY_RANGES || magic_range_is_dsentry(addr)) {
+        MAGIC_DSENTRY_ALIVE_BLOCK_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+            start_address = sentry->address;
+            end_address = (void *) (((char *)sentry->address) +
+                sentry->type->size - 1);
+            if (MAGIC_ADDR_IS_WITHIN(addr, start_address, end_address)) {
+                if (dsentry_buff) {
+                    magic_copy_dsentry(dsentry, dsentry_buff);
+                    entry = MAGIC_DSENTRY_TO_SENTRY(dsentry_buff);
+                }
+                else {
+                    entry = sentry;
+                }
+                break;
+            }
+        );
+    }
+    MAGIC_DSENTRY_UNLOCK();
+#endif
+
+    return entry;
+}
+
+/*===========================================================================*
+ *                    magic_sentry_lookup_by_min_off_by_n                    *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_min_off_by_n(void *addr,
+    int flags, long *min_n_ptr, struct _magic_dsentry *dsentry_buff)
+{
+    int i;
+    struct _magic_sentry *entry = NULL;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry *sentry;
+    long n, abs_n, min_n, min_abs_n = LONG_MAX;
+    int has_multiple_min_entries = FALSE;
+
+    /* Scan all the entries and return the one with the minimum off-by-n. */
+#if MAGIC_LOOKUP_SENTRY
+    for (i = 0 ; i < _magic_sentries_num ; i++) {
+        n = magic_sentry_get_off_by_n(&_magic_sentries[i], addr, flags);
+        abs_n = MAGIC_ABS(n);
+        if (n == LONG_MAX || abs_n > min_abs_n) {
+            continue;
+        }
+        if (abs_n == min_abs_n) {
+            has_multiple_min_entries = TRUE;
+        }
+        else {
+            min_abs_n = abs_n;
+            min_n = n;
+            has_multiple_min_entries = FALSE;
+            entry = &_magic_sentries[i];
+        }
+    }
+#endif
+
+#if MAGIC_LOOKUP_DSENTRY
+    MAGIC_DSENTRY_LOCK();
+    MAGIC_DSENTRY_ALIVE_BLOCK_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+        n = magic_sentry_get_off_by_n(sentry, addr, flags);
+        abs_n = MAGIC_ABS(n);
+        if (n == LONG_MAX || abs_n > min_abs_n) {
+            continue;
+        }
+        if (abs_n == min_abs_n) {
+            has_multiple_min_entries = TRUE;
+        }
+        else {
+            min_abs_n = abs_n;
+            min_n = n;
+            has_multiple_min_entries = FALSE;
+            if (dsentry_buff) {
+                magic_copy_dsentry(dsentry, dsentry_buff);
+                entry = MAGIC_DSENTRY_TO_SENTRY(dsentry_buff);
+            }
+            else {
+                entry = sentry;
+            }
+        }
+    );
+    MAGIC_DSENTRY_UNLOCK();
+#endif
+
+    if (has_multiple_min_entries && (flags & MAGIC_SENTRY_OFF_BY_N_NO_DUPLICATES)) {
+        entry = NULL;
+    }
+    if (entry && min_n_ptr) {
+        *min_n_ptr = min_n;
+    }
+    return entry;
+}
+
+/*===========================================================================*
+ *                       magic_sentry_lookup_by_string                       *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_string(char *string)
+{
+    int i;
+    struct _magic_sentry *entry = NULL;
+
+    /* Scan all the string entries and return the matching one. */
+#if MAGIC_LOOKUP_SENTRY
+    for(i = 0 ; i < _magic_sentries_num ; i++) {
+        if (MAGIC_STATE_FLAG(&_magic_sentries[i], MAGIC_STATE_STRING)
+            && !strcmp((char *)_magic_sentries[i].address, string)) {
+            entry = &_magic_sentries[i];
+            break;
+        }
+    }
+#endif
+
+    return entry;
+}
+
+/*===========================================================================*
+ *                          magic_print_sentry                               *
+ *===========================================================================*/
+PUBLIC void magic_print_sentry(struct _magic_sentry *sentry)
+{
+    MAGIC_SENTRY_PRINT(sentry, MAGIC_EXPAND_TYPE_STR);
+}
+
+/*===========================================================================*
+ *                      magic_print_sentry_abs_name                          *
+ *===========================================================================*/
+PUBLIC void magic_print_sentry_abs_name(struct _magic_sentry *sentry)
+{
+    if (!(sentry->flags & MAGIC_STATE_DYNAMIC)) {
+        _magic_printf(sentry->name);
+    }
+    else {
+        struct _magic_dsentry *dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
+        assert(dsentry->parent_name && strcmp(dsentry->parent_name, ""));
+        assert(sentry->name);
+        assert(strcmp(sentry->name, ""));
+        _magic_printf("%lu%s%s%s%s%s" MAGIC_ID_FORMAT, (unsigned long)MAGIC_SENTRY_ID(sentry),
+            MAGIC_DSENTRY_ABS_NAME_SEP, dsentry->parent_name,
+            MAGIC_DSENTRY_ABS_NAME_SEP, sentry->name,
+            MAGIC_DSENTRY_ABS_NAME_SEP, dsentry->site_id);
+    }
+}
+
+/*===========================================================================*
+ *                         magic_print_sentries                              *
+ *===========================================================================*/
+PUBLIC void magic_print_sentries()
+{
+    int i;
+    struct _magic_sentry* sentry;
+
+    _magic_printf("magic_print_sentries: Printing %d entries\n", _magic_sentries_num);
+    for (i = 0 ; i < _magic_sentries_num ; i++) {
+        sentry = &_magic_sentries[i];
+        MAGIC_SENTRY_PRINT(sentry, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+    }
+}
+
+/*===========================================================================*
+ *                       magic_print_nonstr_sentries                         *
+ *===========================================================================*/
+PUBLIC void magic_print_nonstr_sentries()
+{
+    int i;
+    struct _magic_sentry *sentry;
+
+    _magic_printf("magic_print_nonstr_sentries: Printing %d/%d non-string entries\n",
+        _magic_sentries_num - _magic_sentries_str_num, _magic_sentries_num);
+    for (i = 0 ; i < _magic_sentries_num ; i++) {
+        sentry = &_magic_sentries[i];
+        if (MAGIC_SENTRY_IS_STRING(sentry)) {
+            continue;
+        }
+        MAGIC_SENTRY_PRINT(sentry, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+    }
+}
+
+/*===========================================================================*
+ *                         magic_print_str_sentries                          *
+ *===========================================================================*/
+PUBLIC void magic_print_str_sentries()
+{
+    int i;
+    struct _magic_sentry *sentry;
+
+    _magic_printf("magic_print_str_sentries: Printing %d/%d string entries\n",
+        _magic_sentries_str_num, _magic_sentries_num);
+    for (i = 0 ; i < _magic_sentries_num ; i++) {
+        sentry = &_magic_sentries[i];
+        if (!MAGIC_SENTRY_IS_STRING(sentry)) {
+            continue;
+        }
+        MAGIC_SENTRY_PRINT(sentry, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf(", string=\"%s\"\n", (char*)sentry->address);
+    }
+}
+
+/*===========================================================================*
+ *                           magic_sentry_rl_alloc                           *
+ *===========================================================================*/
+PRIVATE void *magic_sentry_rl_alloc(int size, UNUSED(void *data))
+{
+    void *addr;
+
+    assert(magic_sentry_rl_buff);
+    assert(magic_sentry_rl_buff_offset + size <= magic_sentry_rl_buff_size);
+
+    addr = (char*) magic_sentry_rl_buff + magic_sentry_rl_buff_offset;
+    magic_sentry_rl_buff_offset += size;
+
+    return addr;
+}
+
+/*===========================================================================*
+ *                          magic_sentry_rl_dealloc                          *
+ *===========================================================================*/
+PRIVATE void magic_sentry_rl_dealloc(UNUSED(void *object), UNUSED(void *data))
+{
+    return;
+}
+
+/*===========================================================================*
+ *                         magic_sentry_rl_build_index                       *
+ *===========================================================================*/
+PUBLIC void magic_sentry_rl_build_index(void *buff, size_t buff_size)
+{
+/*
+ * Warning: this implementation is thread unsafe and also makes
+ *              magic_sentry_lookup_by_range thread unsafe!
+ */
+    int i;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry *sentry;
+    void *start_address;
+    splay_tree index;
+
+    assert(buff && buff_size > 0);
+    magic_sentry_rl_buff = buff;
+    magic_sentry_rl_buff_offset = 0;
+    magic_sentry_rl_buff_size = buff_size;
+    index = splay_tree_new_with_allocator(
+        splay_tree_compare_pointers,
+        NULL, NULL,
+        magic_sentry_rl_alloc, magic_sentry_rl_dealloc,
+        NULL);
+    magic_sentry_rl_index = index;
+    assert(magic_sentry_rl_index);
+
+    /* Add all the sentries to the index. */
+#if MAGIC_LOOKUP_SENTRY
+    for (i = 0 ; i < _magic_sentries_num ; i++) {
+        start_address = _magic_sentries[i].address;
+        sentry = &_magic_sentries[i];
+        magic_sentry_rl_insert(start_address, sentry);
+    }
+#endif
+
+    /* Add all the dsentries to the index. */
+#if MAGIC_LOOKUP_DSENTRY
+    MAGIC_DSENTRY_LOCK();
+    MAGIC_DSENTRY_ALIVE_BLOCK_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+        start_address = sentry->address;
+        magic_sentry_rl_insert(start_address, sentry);
+    );
+    MAGIC_DSENTRY_UNLOCK();
+#endif
+}
+
+/*===========================================================================*
+ *                        magic_sentry_rl_destroy_index                      *
+ *===========================================================================*/
+PUBLIC void magic_sentry_rl_destroy_index(void)
+{
+    magic_sentry_rl_buff = NULL;
+    magic_sentry_rl_buff_offset = 0;
+    magic_sentry_rl_buff_size = 0;
+    magic_sentry_rl_index = NULL;
+}
+
+/*===========================================================================*
+ *                    magic_sentry_rl_estimate_index_buff_size               *
+ *===========================================================================*/
+PUBLIC size_t magic_sentry_rl_estimate_index_buff_size(int sentries_num)
+{
+    if (sentries_num == 0) {
+        MAGIC_DSENTRY_ALIVE_BLOCK_NUM(_magic_first_dsentry, &sentries_num);
+        sentries_num += _magic_sentries_num;
+    }
+
+    return (sentries_num * sizeof(struct splay_tree_node_s)) +
+        (sizeof(struct splay_tree_s) * 2);
+}
+
+/*===========================================================================*
+ *                       magic_sentry_rl_count_index_cb                      *
+ *===========================================================================*/
+PRIVATE int magic_sentry_rl_count_index_cb(splay_tree_node node, void *data)
+{
+    size_t *count = (size_t *) data;
+
+    (*count)++;
+    return 0;
+}
+
+/*===========================================================================*
+ *                       magic_sentry_rl_print_index_cb                      *
+ *===========================================================================*/
+PRIVATE int magic_sentry_rl_print_index_cb(splay_tree_node node, void *data)
+{
+    _magic_printf("NODE<key, value>: <%08x, %08x>\n", (unsigned int) node->key,
+        (unsigned int) node->value);
+    return 0;
+}
+
+/*===========================================================================*
+ *                         magic_sentry_rl_print_index                       *
+ *===========================================================================*/
+PUBLIC void magic_sentry_rl_print_index(void)
+{
+    size_t num_nodes = 0;
+    assert(magic_sentry_rl_index);
+
+    splay_tree_foreach((splay_tree) magic_sentry_rl_index,
+        magic_sentry_rl_count_index_cb, &num_nodes);
+    _magic_printf("magic_sentry_rl_print_index: Found %d nodes:\n", num_nodes);
+    splay_tree_foreach((splay_tree) magic_sentry_rl_index,
+        magic_sentry_rl_print_index_cb, NULL);
+}
+
+/*===========================================================================*
+ *                          magic_sentry_rl_lookup                           *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_rl_lookup(void *start_addr)
+{
+    splay_tree_node node;
+    struct _magic_sentry *sentry = NULL;
+
+    node = splay_tree_lookup((splay_tree) magic_sentry_rl_index,
+        (splay_tree_key) start_addr);
+    if (node) {
+        sentry = (struct _magic_sentry*) node->value;
+    }
+
+    return sentry;
+}
+
+/*===========================================================================*
+ *                           magic_sentry_rl_insert                          *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_rl_insert(void *start_addr,
+    struct _magic_sentry *sentry)
+{
+    if (!splay_tree_lookup((splay_tree) magic_sentry_rl_index,
+        (splay_tree_key) start_addr)) {
+        splay_tree_insert((splay_tree) magic_sentry_rl_index,
+            (splay_tree_key) start_addr,
+            (splay_tree_value) sentry);
+    }
+    else {
+        sentry = NULL;
+    }
+
+    return sentry;
+}
+
+/*===========================================================================*
+ *                        magic_sentry_rl_pred_lookup                        *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_rl_pred_lookup(void *addr)
+{
+    splay_tree_node node;
+    struct _magic_sentry *sentry = NULL;
+
+    node = splay_tree_predecessor((splay_tree) magic_sentry_rl_index,
+        (splay_tree_key) addr);
+    if (node) {
+        sentry = (struct _magic_sentry*) node->value;
+    }
+
+    return sentry;
+}
+
+/*===========================================================================*
+ *                      magic_sentry_lookup_by_range_index                   *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_range_index(
+    void *addr, struct _magic_dsentry *dsentry_buff)
+{
+    /*
+     * Warning: this implementation is thread unsafe!
+     */
+    void *start_address, *end_address;
+    struct _magic_sentry *sentry =
+        magic_sentry_rl_pred_lookup((char *)addr + 1);
+
+    if (sentry) {
+        start_address = sentry->address;
+        end_address = (void *) (((char *)start_address) +
+            sentry->type->size - 1);
+        if (!MAGIC_ADDR_IS_WITHIN(addr, start_address, end_address)) {
+            sentry = NULL;
+        } else {
+            if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_DYNAMIC) &&
+                dsentry_buff != NULL) {
+                magic_copy_dsentry(MAGIC_DSENTRY_FROM_SENTRY(sentry),
+                    dsentry_buff);
+            }
+        }
+    }
+
+    return sentry;
+}
+
+/*===========================================================================*
+ *                         magic_sentry_hash_insert                          *
+ *===========================================================================*/
+PRIVATE void magic_sentry_hash_insert(struct _magic_sentry_hash **head,
+    struct _magic_sentry_hash *elem)
+{
+    if (head != NULL) {
+        struct _magic_sentry_hash *tmp;
+        HASH_FIND_STR(*head, elem->key, tmp);
+        if (tmp) {
+            LL_APPEND(tmp->sentry_list, elem->sentry_list);
+            return;
+        }
+    }
+/*
+ * **** START UTHASH SPECIFIC DEFINITIONS ****
+ */
+#undef uthash_malloc
+#undef uthash_free
+#define uthash_malloc(size)             magic_sentry_hash_alloc(size)
+#define uthash_free(addr, size)         magic_sentry_hash_dealloc(addr, size)
+/*
+ * Since we have a limited buffer, we need to stop bucket expansion when
+ * reaching a certain limit.
+ */
+#undef uthash_expand_fyi
+#define uthash_expand_fyi(tbl)                                                 \
+    do {                                                                       \
+        if (tbl->num_buckets == MAGIC_SENTRY_NAME_EST_MAX_BUCKETS) {           \
+            _magic_printf("Warning! Sentry name hash maximum bucket number "   \
+                "reached! Consider increasing "                                \
+                "MAGIC_SENTRY_NAME_EST_MAX_BUCKETS, unless you are comfortable"\
+                " with the current performance.\n");                           \
+            tbl->noexpand = 1;                                                 \
+        }                                                                      \
+    } while(0);
+/*
+ * **** FINISH UTHASH SPECIFIC DEFINITIONS ****
+ */
+    HASH_ADD_STR(*head, key, elem);
+/*
+ * **** START UTHASH DEFINITION REMOVAL ****
+ */
+#undef uthash_malloc
+#undef uthash_free
+#undef uthash_expand_fyi
+/*
+ * **** FINISH UTHASH DEFINITION REMOVAL ****
+ */
+}
+
+/*===========================================================================*
+ *                         magic_sentry_hash_build                           *
+ *===========================================================================*/
+PUBLIC void magic_sentry_hash_build(void *buff, size_t buff_size)
+{
+    /*
+     * XXX:
+     * Warning: this implementation is thread unsafe and also makes
+     * magic_sentry_lookup_by_name thread unsafe!
+     */
+    int i;
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry *sentry;
+    struct _magic_sentry_hash *sentry_hash, *head;
+    struct _magic_sentry_list *sentry_list;
+
+    assert(buff && buff_size > 0);
+    magic_sentry_hash_buff = buff;
+    magic_sentry_hash_buff_offset = 0;
+    magic_sentry_hash_buff_size = buff_size;
+
+    head = NULL;
+
+    /* Add all the sentries to the hash. */
+#if MAGIC_LOOKUP_SENTRY
+    for(i = 0 ; i < _magic_sentries_num ; i++) {
+        sentry_hash = (struct _magic_sentry_hash *)
+            magic_sentry_hash_alloc(sizeof(struct _magic_sentry_hash));
+        sentry_list = (struct _magic_sentry_list *)
+            magic_sentry_hash_alloc(sizeof(struct _magic_sentry_list));
+        sentry = &_magic_sentries[i];
+        MAGIC_SENTRY_TO_HASH_EL(sentry, sentry_hash, sentry_list);
+        magic_sentry_hash_insert(&head, sentry_hash);
+    }
+#endif
+
+    /* Add all the dsentries to the hash. */
+#if MAGIC_LOOKUP_DSENTRY
+    MAGIC_DSENTRY_LOCK();
+    MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+        sentry_hash = (struct _magic_sentry_hash *)
+            magic_sentry_hash_alloc(sizeof(struct _magic_sentry_hash));
+        sentry_list = (struct _magic_sentry_list *)
+            magic_sentry_hash_alloc(sizeof(struct _magic_sentry_list));
+        MAGIC_DSENTRY_TO_HASH_EL(dsentry, sentry, sentry_hash, sentry_list);
+        magic_sentry_hash_insert(&head, sentry_hash);
+    );
+    MAGIC_DSENTRY_UNLOCK();
+#endif
+    magic_sentry_hash_head = (void *)head;
+    assert(magic_sentry_hash_head || (!_magic_sentries_num && _magic_first_dsentry == NULL));
+}
+
+/*===========================================================================*
+ *                        magic_sentry_hash_destroy                          *
+ *===========================================================================*/
+PUBLIC void magic_sentry_hash_destroy(void)
+{
+    magic_sentry_hash_buff = NULL;
+    magic_sentry_hash_buff_offset = 0;
+    magic_sentry_hash_buff_size = 0;
+    magic_sentry_hash_head = NULL;
+}
+
+/*===========================================================================*
+ *                    magic_sentry_hash_estimate_buff_size                   *
+ *===========================================================================*/
+PUBLIC size_t magic_sentry_hash_estimate_buff_size(int sentries_num)
+{
+    if (sentries_num == 0) {
+        MAGIC_DSENTRY_ALIVE_NUM(_magic_first_dsentry, &sentries_num);
+        sentries_num += _magic_sentries_num;
+    }
+
+    return (sentries_num * (sizeof(struct _magic_sentry_hash) +
+        sizeof(struct _magic_sentry_list))) + MAGIC_SENTRY_NAME_HASH_OVERHEAD;
+}
+
+/*===========================================================================*
+ *                           magic_sentry_hash_alloc                         *
+ *===========================================================================*/
+PUBLIC void *magic_sentry_hash_alloc(size_t size)
+{
+    void *addr;
+
+    assert(magic_sentry_hash_buff);
+    assert(magic_sentry_hash_buff_offset + size <= magic_sentry_hash_buff_size);
+
+    addr = (char *) magic_sentry_hash_buff + magic_sentry_hash_buff_offset;
+    magic_sentry_hash_buff_offset += size;
+
+    return addr;
+}
+
+/*===========================================================================*
+ *                          magic_sentry_hash_dealloc                        *
+ *===========================================================================*/
+PUBLIC void magic_sentry_hash_dealloc(UNUSED(void *object), UNUSED(size_t sz))
+{
+    return;
+}
+
+/*===========================================================================*
+ *                      magic_sentry_lookup_by_name_hash                     *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry *magic_sentry_lookup_by_name_hash(
+    char *parent_name, char *name, _magic_id_t site_id,
+    struct _magic_dsentry *dsentry_buff)
+{
+    /*
+     * Warning: this implementation is thread unsafe!
+     */
+    char key[MAGIC_SENTRY_NAME_MAX_KEY_LEN];
+    struct _magic_sentry_hash *res, *head;
+    key[0] = 0;
+    sprintf(key, "%s%s%s%s" MAGIC_ID_FORMAT, parent_name,
+        MAGIC_DSENTRY_ABS_NAME_SEP, name, MAGIC_DSENTRY_ABS_NAME_SEP, site_id);
+    head = (struct _magic_sentry_hash *) magic_sentry_hash_head;
+
+    HASH_FIND_STR(head, key, res);
+    if (res == NULL)
+        return NULL;
+
+    return res->sentry_list->sentry;
+}
+
+/*===========================================================================*
+ *                    magic_sentry_list_lookup_by_name_hash                  *
+ *===========================================================================*/
+PUBLIC struct _magic_sentry_list *magic_sentry_list_lookup_by_name_hash(
+    char *parent_name, char *name, _magic_id_t site_id,
+    struct _magic_dsentry *dsentry_buff)
+{
+    /*
+     * Warning: this implementation is thread unsafe!
+     */
+    char key[MAGIC_SENTRY_NAME_MAX_KEY_LEN];
+    struct _magic_sentry_hash *res, *head;
+    key[0] = 0;
+    sprintf(key, "%s%s%s%s" MAGIC_ID_FORMAT, parent_name,
+        MAGIC_DSENTRY_ABS_NAME_SEP, name, MAGIC_DSENTRY_ABS_NAME_SEP, site_id);
+    head = (struct _magic_sentry_hash *) magic_sentry_hash_head;
+
+    HASH_FIND_STR(head, key, res);
+    if (res == NULL)
+        return NULL;
+
+    return res->sentry_list;
+}
+
diff --git a/minix/llvm/static/magic/magic_splay_tree.c b/minix/llvm/static/magic/magic_splay_tree.c
new file mode 100644 (file)
index 0000000..e8247ed
--- /dev/null
@@ -0,0 +1,523 @@
+/* A splay-tree datatype.
+   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by Mark Mitchell (mark@markmitchell.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+/* For an easily readable description of splay-trees, see:
+
+     Lewis, Harry R. and Denenberg, Larry.  Data Structures and Their
+     Algorithms.  Harper-Collins, Inc.  1991.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "magic_splay_tree.h"
+
+#ifndef xmalloc
+#define xmalloc malloc
+#endif
+
+static void splay_tree_delete_helper (splay_tree, splay_tree_node);
+static inline void rotate_left (splay_tree_node *,
+                splay_tree_node, splay_tree_node);
+static inline void rotate_right (splay_tree_node *,
+                splay_tree_node, splay_tree_node);
+static void splay_tree_splay (splay_tree, splay_tree_key);
+static int splay_tree_foreach_helper (splay_tree, splay_tree_node,
+                                      splay_tree_foreach_fn, void*);
+
+/* Deallocate NODE (a member of SP), and all its sub-trees.  */
+
+static void
+splay_tree_delete_helper (splay_tree sp, splay_tree_node node)
+{
+  splay_tree_node pending = 0;
+  splay_tree_node active = 0;
+
+  if (!node)
+    return;
+
+#define KDEL(x)  if (sp->delete_key) (*sp->delete_key)(x);
+#define VDEL(x)  if (sp->delete_value) (*sp->delete_value)(x);
+
+  KDEL (node->key);
+  VDEL (node->value);
+
+  /* We use the "key" field to hold the "next" pointer.  */
+  node->key = (splay_tree_key)pending;
+  pending = (splay_tree_node)node;
+
+  /* Now, keep processing the pending list until there aren't any
+     more.  This is a little more complicated than just recursing, but
+     it doesn't toast the stack for large trees.  */
+
+  while (pending)
+    {
+      active = pending;
+      pending = 0;
+      while (active)
+    {
+      splay_tree_node temp;
+
+      /* active points to a node which has its key and value
+         deallocated, we just need to process left and right.  */
+
+      if (active->left)
+        {
+          KDEL (active->left->key);
+          VDEL (active->left->value);
+          active->left->key = (splay_tree_key)pending;
+          pending = (splay_tree_node)(active->left);
+        }
+      if (active->right)
+        {
+          KDEL (active->right->key);
+          VDEL (active->right->value);
+          active->right->key = (splay_tree_key)pending;
+          pending = (splay_tree_node)(active->right);
+        }
+
+      temp = active;
+      active = (splay_tree_node)(temp->key);
+      (*sp->deallocate) ((char*) temp, sp->allocate_data);
+    }
+    }
+#undef KDEL
+#undef VDEL
+}
+
+/* Rotate the edge joining the left child N with its parent P.  PP is the
+   grandparents pointer to P.  */
+
+static inline void
+rotate_left (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
+{
+  splay_tree_node tmp;
+  tmp = n->right;
+  n->right = p;
+  p->left = tmp;
+  *pp = n;
+}
+
+/* Rotate the edge joining the right child N with its parent P.  PP is the
+   grandparents pointer to P.  */
+
+static inline void
+rotate_right (splay_tree_node *pp, splay_tree_node p, splay_tree_node n)
+{
+  splay_tree_node tmp;
+  tmp = n->left;
+  n->left = p;
+  p->right = tmp;
+  *pp = n;
+}
+
+/* Bottom up splay of key.  */
+
+static void
+splay_tree_splay (splay_tree sp, splay_tree_key key)
+{
+  if (sp->root == 0)
+    return;
+
+  do {
+    int cmp1, cmp2;
+    splay_tree_node n, c;
+
+    n = sp->root;
+    cmp1 = (*sp->comp) (key, n->key);
+
+    /* Found.  */
+    if (cmp1 == 0)
+      return;
+
+    /* Left or right?  If no child, then we're done.  */
+    if (cmp1 < 0)
+      c = n->left;
+    else
+      c = n->right;
+    if (!c)
+      return;
+
+    /* Next one left or right?  If found or no child, we're done
+       after one rotation.  */
+    cmp2 = (*sp->comp) (key, c->key);
+    if (cmp2 == 0
+        || (cmp2 < 0 && !c->left)
+        || (cmp2 > 0 && !c->right))
+      {
+    if (cmp1 < 0)
+      rotate_left (&sp->root, n, c);
+    else
+      rotate_right (&sp->root, n, c);
+        return;
+      }
+
+    /* Now we have the four cases of double-rotation.  */
+    if (cmp1 < 0 && cmp2 < 0)
+      {
+    rotate_left (&n->left, c, c->left);
+    rotate_left (&sp->root, n, n->left);
+      }
+    else if (cmp1 > 0 && cmp2 > 0)
+      {
+    rotate_right (&n->right, c, c->right);
+    rotate_right (&sp->root, n, n->right);
+      }
+    else if (cmp1 < 0 && cmp2 > 0)
+      {
+    rotate_right (&n->left, c, c->right);
+    rotate_left (&sp->root, n, n->left);
+      }
+    else if (cmp1 > 0 && cmp2 < 0)
+      {
+    rotate_left (&n->right, c, c->left);
+    rotate_right (&sp->root, n, n->right);
+      }
+  } while (1);
+}
+
+/* Call FN, passing it the DATA, for every node below NODE, all of
+   which are from SP, following an in-order traversal.  If FN every
+   returns a non-zero value, the iteration ceases immediately, and the
+   value is returned.  Otherwise, this function returns 0.  */
+
+static int
+splay_tree_foreach_helper (splay_tree sp, splay_tree_node node,
+                           splay_tree_foreach_fn fn, void *data)
+{
+  int val;
+
+  if (!node)
+    return 0;
+
+  val = splay_tree_foreach_helper (sp, node->left, fn, data);
+  if (val)
+    return val;
+
+  val = (*fn)(node, data);
+  if (val)
+    return val;
+
+  return splay_tree_foreach_helper (sp, node->right, fn, data);
+}
+
+
+/* An allocator and deallocator based on xmalloc.  */
+static void *
+splay_tree_xmalloc_allocate (int size, void *data ATTRIBUTE_UNUSED)
+{
+  return (void *) xmalloc (size);
+}
+
+static void
+splay_tree_xmalloc_deallocate (void *object, void *data ATTRIBUTE_UNUSED)
+{
+  free (object);
+}
+
+
+/* Allocate a new splay tree, using COMPARE_FN to compare nodes,
+   DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
+   values.  Use xmalloc to allocate the splay tree structure, and any
+   nodes added.  */
+
+splay_tree
+splay_tree_new (splay_tree_compare_fn compare_fn,
+                splay_tree_delete_key_fn delete_key_fn,
+                splay_tree_delete_value_fn delete_value_fn)
+{
+  return (splay_tree_new_with_allocator
+          (compare_fn, delete_key_fn, delete_value_fn,
+           splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate, 0));
+}
+
+
+/* Allocate a new splay tree, using COMPARE_FN to compare nodes,
+   DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate
+   values.  */
+
+splay_tree
+splay_tree_new_with_allocator (splay_tree_compare_fn compare_fn,
+                               splay_tree_delete_key_fn delete_key_fn,
+                               splay_tree_delete_value_fn delete_value_fn,
+                               splay_tree_allocate_fn allocate_fn,
+                               splay_tree_deallocate_fn deallocate_fn,
+                               void *allocate_data)
+{
+  splay_tree sp = (splay_tree) (*allocate_fn) (sizeof (struct splay_tree_s),
+                                               allocate_data);
+  sp->root = 0;
+  sp->comp = compare_fn;
+  sp->delete_key = delete_key_fn;
+  sp->delete_value = delete_value_fn;
+  sp->allocate = allocate_fn;
+  sp->deallocate = deallocate_fn;
+  sp->allocate_data = allocate_data;
+
+  return sp;
+}
+
+/* Deallocate SP.  */
+
+void
+splay_tree_delete (splay_tree sp)
+{
+  splay_tree_delete_helper (sp, sp->root);
+  (*sp->deallocate) ((char*) sp, sp->allocate_data);
+}
+
+/* Insert a new node (associating KEY with DATA) into SP.  If a
+   previous node with the indicated KEY exists, its data is replaced
+   with the new value.  Returns the new node.  */
+
+splay_tree_node
+splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value)
+{
+  int comparison = 0;
+
+  splay_tree_splay (sp, key);
+
+  if (sp->root)
+    comparison = (*sp->comp)(sp->root->key, key);
+
+  if (sp->root && comparison == 0)
+    {
+      /* If the root of the tree already has the indicated KEY, just
+     replace the value with VALUE.  */
+      if (sp->delete_value)
+    (*sp->delete_value)(sp->root->value);
+      sp->root->value = value;
+    }
+  else
+    {
+      /* Create a new node, and insert it at the root.  */
+      splay_tree_node node;
+
+      node = ((splay_tree_node)
+              (*sp->allocate) (sizeof (struct splay_tree_node_s),
+                               sp->allocate_data));
+      node->key = key;
+      node->value = value;
+
+      if (!sp->root)
+    node->left = node->right = 0;
+      else if (comparison < 0)
+    {
+      node->left = sp->root;
+      node->right = node->left->right;
+      node->left->right = 0;
+    }
+      else
+    {
+      node->right = sp->root;
+      node->left = node->right->left;
+      node->right->left = 0;
+    }
+
+      sp->root = node;
+    }
+
+  return sp->root;
+}
+
+/* Remove KEY from SP.  It is not an error if it did not exist.  */
+
+void
+splay_tree_remove (splay_tree sp, splay_tree_key key)
+{
+  splay_tree_splay (sp, key);
+
+  if (sp->root && (*sp->comp) (sp->root->key, key) == 0)
+    {
+      splay_tree_node left, right;
+
+      left = sp->root->left;
+      right = sp->root->right;
+
+      /* Delete the root node itself.  */
+      if (sp->delete_value)
+    (*sp->delete_value) (sp->root->value);
+      (*sp->deallocate) (sp->root, sp->allocate_data);
+
+      /* One of the children is now the root.  Doesn't matter much
+     which, so long as we preserve the properties of the tree.  */
+      if (left)
+    {
+      sp->root = left;
+
+      /* If there was a right child as well, hang it off the
+         right-most leaf of the left child.  */
+      if (right)
+        {
+          while (left->right)
+        left = left->right;
+          left->right = right;
+        }
+    }
+      else
+    sp->root = right;
+    }
+}
+
+/* Lookup KEY in SP, returning VALUE if present, and NULL
+   otherwise.  */
+
+splay_tree_node
+splay_tree_lookup (splay_tree sp, splay_tree_key key)
+{
+  splay_tree_splay (sp, key);
+
+  if (sp->root && (*sp->comp)(sp->root->key, key) == 0)
+    return sp->root;
+  else
+    return 0;
+}
+
+/* Return the node in SP with the greatest key.  */
+
+splay_tree_node
+splay_tree_max (splay_tree sp)
+{
+  splay_tree_node n = sp->root;
+
+  if (!n)
+    return NULL;
+
+  while (n->right)
+    n = n->right;
+
+  return n;
+}
+
+/* Return the node in SP with the smallest key.  */
+
+splay_tree_node
+splay_tree_min (splay_tree sp)
+{
+  splay_tree_node n = sp->root;
+
+  if (!n)
+    return NULL;
+
+  while (n->left)
+    n = n->left;
+
+  return n;
+}
+
+/* Return the immediate predecessor KEY, or NULL if there is no
+   predecessor.  KEY need not be present in the tree.  */
+
+splay_tree_node
+splay_tree_predecessor (splay_tree sp, splay_tree_key key)
+{
+  int comparison;
+  splay_tree_node node;
+
+  /* If the tree is empty, there is certainly no predecessor.  */
+  if (!sp->root)
+    return NULL;
+
+  /* Splay the tree around KEY.  That will leave either the KEY
+     itself, its predecessor, or its successor at the root.  */
+  splay_tree_splay (sp, key);
+  comparison = (*sp->comp)(sp->root->key, key);
+
+  /* If the predecessor is at the root, just return it.  */
+  if (comparison < 0)
+    return sp->root;
+
+  /* Otherwise, find the rightmost element of the left subtree.  */
+  node = sp->root->left;
+  if (node)
+    while (node->right)
+      node = node->right;
+
+  return node;
+}
+
+/* Return the immediate successor KEY, or NULL if there is no
+   successor.  KEY need not be present in the tree.  */
+
+splay_tree_node
+splay_tree_successor (splay_tree sp, splay_tree_key key)
+{
+  int comparison;
+  splay_tree_node node;
+
+  /* If the tree is empty, there is certainly no successor.  */
+  if (!sp->root)
+    return NULL;
+
+  /* Splay the tree around KEY.  That will leave either the KEY
+     itself, its predecessor, or its successor at the root.  */
+  splay_tree_splay (sp, key);
+  comparison = (*sp->comp)(sp->root->key, key);
+
+  /* If the successor is at the root, just return it.  */
+  if (comparison > 0)
+    return sp->root;
+
+  /* Otherwise, find the leftmost element of the right subtree.  */
+  node = sp->root->right;
+  if (node)
+    while (node->left)
+      node = node->left;
+
+  return node;
+}
+
+/* Call FN, passing it the DATA, for every node in SP, following an
+   in-order traversal.  If FN every returns a non-zero value, the
+   iteration ceases immediately, and the value is returned.
+   Otherwise, this function returns 0.  */
+
+int
+splay_tree_foreach (splay_tree sp, splay_tree_foreach_fn fn, void *data)
+{
+  return splay_tree_foreach_helper (sp, sp->root, fn, data);
+}
+
+/* Splay-tree comparison function, treating the keys as ints.  */
+
+int
+splay_tree_compare_ints (splay_tree_key k1, splay_tree_key k2)
+{
+  if ((int) k1 < (int) k2)
+    return -1;
+  else if ((int) k1 > (int) k2)
+    return 1;
+  else
+    return 0;
+}
+
+/* Splay-tree comparison function, treating the keys as pointers.  */
+
+int
+splay_tree_compare_pointers (splay_tree_key k1, splay_tree_key k2)
+{
+  if ((char*) k1 < (char*) k2)
+    return -1;
+  else if ((char*) k1 > (char*) k2)
+    return 1;
+  else
+    return 0;
+}
+
diff --git a/minix/llvm/static/magic/magic_st.c b/minix/llvm/static/magic/magic_st.c
new file mode 100644 (file)
index 0000000..69fcc0d
--- /dev/null
@@ -0,0 +1,4542 @@
+#include <magic.h>
+#include <magic_mem.h>
+#include <magic_analysis.h>
+#include <magic_asr.h>
+#include <stdarg.h>
+#include <st/state_transfer.h>
+#include <st/metadata_transfer.h>
+#include <st/typedefs.h>
+#include <st/private.h>
+
+#define printf _magic_printf
+
+#ifdef __MINIX
+EXTERN endpoint_t sef_self_endpoint;
+#else
+#define DO_SKIP_ENVIRON_HACK 1
+#define TODO_DSENTRY_PARENT_NAME_BUG 1
+#define DO_SKIP_UNPAIRED_PTR_TARGETS 1
+#endif
+
+#define DO_SKIP_INVARIANTS_VIOLATIONS 1
+
+PRIVATE st_alloc_pages *st_alloc_pages_current = NULL;
+PRIVATE int st_alloc_buff_available = 0;
+PRIVATE char *st_alloc_buff_pt = NULL;
+PRIVATE char *st_pre_allocated_page_pt = NULL;
+PRIVATE struct _magic_dsentry *st_dsentry_buff = NULL;
+PRIVATE void *st_data_buff = NULL;
+PRIVATE unsigned st_num_type_transformations = 0;
+
+/* Magic variables and counterparts. */
+struct _magic_vars_t st_remote_magic_vars, st_cached_magic_vars;
+struct _magic_vars_t *st_local_magic_vars_ptr = &_magic_vars_buff;
+st_counterparts_t st_counterparts;
+
+/* Private variables. */
+PRIVATE int st_init_done = FALSE;
+PRIVATE int st_policies = ST_POLICIES_DEFAULT;
+PRIVATE double st_unpaired_types_ratio = ST_UNPAIRED_TYPES_RATIO_DEFAULT;
+PRIVATE double st_unpaired_struct_types_ratio = ST_UNPAIRED_STRUCT_TYPES_RATIO_DEFAULT;
+
+/* Forward declarations. */
+PRIVATE INLINE int default_transfer_selement_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
+
+/* State transfer callbacks. */
+
+PRIVATE struct st_cbs_t st_cbs = {
+    ST_CB_PAGES_ALLOCATE_DEFAULT,
+    ST_CB_PAGES_FREE_DEFAULT,
+    ST_CB_STATE_CLEANUP_DEFAULT,
+    ST_CB_STATE_CHECKING_DEFAULT,
+    ST_CB_SELEMENT_MAP_DEFAULT,
+    ST_CB_SELEMENT_TRANSFER_EMPTY
+};
+
+/* OS dependent callbacks. */
+PRIVATE struct st_cbs_os_t st_cbs_os = {
+    ST_CB_OS_PANIC_EMPTY,
+    ST_CB_OS_OLD_STATE_TABLE_LOOKUP_EMPTY,
+    ST_CB_OS_COPY_STATE_REGION_EMPTY,
+    ST_CB_OS_ALLOC_CONTIG_EMPTY,
+    ST_CB_OS_FREE_CONTIG_EMPTY,
+    ST_CB_OS_DEBUG_HEADER_EMPTY
+};
+
+/* State transfer prototypes for st_receive(). */
+PUBLIC void do_st_before_receive(void);
+
+/* Callback setters */
+
+PUBLIC void st_setcb_pages_allocate (st_cb_pages_allocate_t cb)
+{
+  assert(cb != NULL);
+  st_cbs.st_cb_pages_allocate = cb;
+}
+
+PUBLIC void st_setcb_pages_free (st_cb_pages_free_t cb)
+{
+  assert(cb != NULL);
+  st_cbs.st_cb_pages_free = cb;
+}
+
+PUBLIC void st_setcb_state_cleanup (st_cb_state_cleanup_t cb)
+{
+  assert(cb != NULL);
+  st_cbs.st_cb_state_cleanup = cb;
+  magic_setcb_sentries_analyze_pre(cb);
+}
+
+PUBLIC void st_setcb_state_checking (st_cb_state_checking_t cb)
+{
+  assert(cb != NULL);
+  st_cbs.st_cb_state_checking = cb;
+}
+
+PUBLIC void st_setcb_selement_map(st_cb_selement_map_t cb)
+{
+  assert(cb != NULL);
+  st_cbs.st_cb_selement_map = cb;
+}
+
+PUBLIC void st_setcb_selement_transfer(st_cb_selement_transfer_t cb, int flags)
+{
+    int i, j;
+    for (i = 0 ; i < NUM_CB_ARRAYS ; i++) {
+        if (i & flags) {
+            int is_registered = FALSE;
+            for (j = 0; j < MAX_NUM_CBS ; j++) {
+                if (st_cbs.st_cb_selement_transfer[i][j] == NULL) {
+                    st_cbs.st_cb_selement_transfer[i][j] = cb;
+                    is_registered = TRUE;
+                    break;
+                }
+            }
+            assert(is_registered && "Number of registered callbacks exceeds MAX_NUM_CBS");
+        }
+    }
+}
+
+/* OS Callback setters. */
+
+PUBLIC void st_setcb_os_panic(st_cb_os_panic_t cb)
+{
+    assert(cb != NULL && "No callback defined for panic().");
+    st_cbs_os.panic = cb;
+}
+
+PUBLIC void st_setcb_os_old_state_table_lookup(st_cb_os_old_state_table_lookup_t cb)
+{
+    assert(cb != NULL && "No callback defined for old_state_table_lookup().");
+    st_cbs_os.old_state_table_lookup = cb;
+}
+
+PUBLIC void st_setcb_os_copy_state_region(st_cb_os_copy_state_region_t cb)
+{
+    assert(cb != NULL && "No callback defined for copy_state_region().");
+    st_cbs_os.copy_state_region = cb;
+}
+
+PUBLIC void st_setcb_os_alloc_contig(st_cb_os_alloc_contig_t cb)
+{
+    assert(cb != NULL && "No callback defined for alloc_contig().");
+    st_cbs_os.alloc_contig = cb;
+}
+
+PUBLIC void st_setcb_os_free_contig(st_cb_os_free_contig_t cb)
+{
+    assert(cb != NULL && "No callback defined for free_contig().");
+    st_cbs_os.free_contig = cb;
+}
+
+PUBLIC void st_setcb_os_debug_header(st_cb_os_debug_header_t cb)
+{
+    assert(cb != NULL && "No callback defined for debug_header().");
+    st_cbs_os.debug_header = cb;
+}
+
+
+PUBLIC void st_setcb_os_all(struct st_cbs_os_t *cbs)
+{
+    st_setcb_os_panic(cbs->panic);
+    st_setcb_os_old_state_table_lookup(cbs->old_state_table_lookup);
+    st_setcb_os_copy_state_region(cbs->copy_state_region);
+    st_setcb_os_alloc_contig(cbs->alloc_contig);
+    st_setcb_os_free_contig(cbs->free_contig);
+    st_setcb_os_debug_header(cbs->debug_header);
+}
+
+/* Status variables to be transfered at state transfer time. */
+PUBLIC int __st_before_receive_enabled = 0;
+PRIVATE int __st_before_receive_sc_max_cycles;
+PRIVATE int __st_before_receive_sc_max_violations;
+
+/* Typedef registration and lookup */
+
+int st_strcmp_wildcard(char *with_wildcard, char *without_wildcard)
+{
+    /* Note: this implementation only supports basic regexes with a '*'
+     * at the beginning or the end of the string.
+     */
+    char *star = strchr(with_wildcard, '*');
+    if (star) {
+        if (star == with_wildcard) {
+            size_t len = strlen(with_wildcard+1);
+            size_t len_without_wildcard = strlen(without_wildcard);
+            char *match_without_wildcard = without_wildcard+
+                len_without_wildcard-len;
+            if (match_without_wildcard < without_wildcard) {
+                return -1;
+            }
+            return strncmp(with_wildcard+1, match_without_wildcard, len);
+        }
+        return strncmp(with_wildcard, without_wildcard, star - with_wildcard);
+    }
+    return strcmp(with_wildcard, without_wildcard);
+}
+
+char *st_typename_noxfers[] =   { ST_TYPENAME_NO_TRANSFER_NAMES, NULL         };
+char *st_typename_ixfers[] =    { ST_TYPENAME_IDENTITY_TRANSFER_NAMES, NULL   };
+char *st_typename_cixfers[] =   { ST_TYPENAME_CIDENTITY_TRANSFER_NAMES, NULL  };
+char *st_typename_pxfers[] =    { ST_TYPENAME_PTR_TRANSFER_NAMES, NULL        };
+char *st_typename_sxfers[] =    { ST_TYPENAME_STRUCT_TRANSFER_NAMES, NULL     };
+char *st_sentryname_ixfers[] =  { ST_SENTRYNAME_IDENTITY_TRANSFER_NAMES, NULL };
+char *st_sentryname_cixfers[] = { ST_SENTRYNAME_CIDENTITY_TRANSFER_NAMES, NULL};
+char *st_sentryname_pxfers[] =  { ST_SENTRYNAME_PTR_TRANSFER_NAMES, NULL      };
+
+/* Exclude stack references in addition to the default sentry names from state transfer. */
+char *st_sentryname_noxfers[] = {
+    ST_SENTRYNAME_NO_TRANSFER_NAMES,
+#define __X(R) #R   /* Stringify the symbol names. */
+    ST_STACK_REFS_INT_LIST,
+#if ST_STACK_REFS_CUSTOM_NUM > 0
+    ST_STACK_REFS_CUSTOM_LIST,
+#endif
+#undef __X
+    NULL };
+
+/* Exclude the data segments of certain libs from state transfer. */
+char *st_dsentry_lib_noxfer[] = {
+#ifdef ST_DSENTRYLIB_NO_TRANSFER_NAMES
+    ST_DSENTRYLIB_NO_TRANSFER_NAMES,
+#endif
+    NULL };
+
+char *st_typename_key_registrations[MAX_NUM_TYPENAMES];
+
+int is_typename(char *search_key, struct _magic_type *type)
+{
+    int i;
+    /* We can't use a cached lookup result */
+    if (!st_strcmp_wildcard(search_key, type->name)) {
+        /* The name matches */
+        return TRUE;
+    }
+    for (i = 0 ; i < type->num_names ; i++) {
+        if(!st_strcmp_wildcard(search_key, type->names[i])) {
+            /* One of the typename names matches */
+            return TRUE;
+        }
+    }
+    /* No match is found */
+    return FALSE;
+}
+
+PUBLIC void st_register_typename_key(char *key)
+{
+    int i, is_registered = FALSE;
+    for(i = 0 ; i < MAX_NUM_TYPENAMES ; i++) {
+        if (st_typename_key_registrations[i] == NULL) {
+            st_typename_key_registrations[i] = key;
+            is_registered = TRUE;
+            break;
+        }
+    }
+    assert(is_registered && "Error, number of typename registrations > MAX_NUM_TYPENAMES.\n");
+}
+
+PUBLIC void st_register_typename_keys(char **keys)
+{
+    int i = 0;
+    while (keys[i] != NULL) {
+        st_register_typename_key(keys[i]);
+        i++;
+    }
+}
+
+PRIVATE void set_typename_key(struct _magic_type *type)
+{
+    char **registration = st_typename_key_registrations;
+
+    while (*registration != NULL) {
+        if (is_typename(*registration, type)) {
+            type->ext = *registration;
+            break;
+        }
+        registration++;
+    }
+}
+
+PUBLIC void register_typenames()
+{
+
+    int i;
+
+    /* Register typenames */
+    st_register_typename_keys(st_typename_noxfers);
+    st_register_typename_keys(st_typename_ixfers);
+    st_register_typename_keys(st_typename_cixfers);
+    st_register_typename_keys(st_typename_pxfers);
+    st_register_typename_keys(st_typename_sxfers);
+
+    for(i = 0 ; i < _magic_types_num ; i++) {
+        set_typename_key(&_magic_types[i]);
+    }
+
+}
+
+PRIVATE INLINE void register_typenames_and_callbacks()
+{
+
+    static int st_is_registered = FALSE;
+    if(st_is_registered) {
+        return;
+    }
+
+    register_typenames();
+
+    st_setcb_selement_transfer(st_cb_transfer_sentry_default, ST_CB_TYPE_SENTRY);
+    st_setcb_selement_transfer(st_cb_transfer_typename_default, ST_CB_TYPE_TYPENAME);
+
+    st_is_registered = TRUE;
+
+}
+
+PUBLIC int st_type_name_match_any(char **registered_type_name_keys,
+    char *key)
+{
+    int i = 0;
+    while (registered_type_name_keys[i] != NULL) {
+        if (ST_TYPE_NAME_MATCH(registered_type_name_keys[i], key)) {
+            return TRUE;
+        }
+        i++;
+    }
+    return FALSE;
+}
+
+PUBLIC int st_sentry_name_match_any(char **sentry_wildcard_names,
+    char *name)
+{
+    int i = 0;
+    while (sentry_wildcard_names[i] != NULL) {
+        if (ST_SENTRY_NAME_MATCH(sentry_wildcard_names[i], name)) {
+            return TRUE;
+        }
+        i++;
+    }
+    return FALSE;
+}
+
+PUBLIC int st_dsentry_parent_name_match_any(char **wildcard_names,
+    char *name)
+{
+    int i = 0;
+    while (wildcard_names[i] != NULL) {
+        if (ST_DSENTRY_PARENT_NAME_MATCH(wildcard_names[i], name)) {
+            return TRUE;
+        }
+        i++;
+    }
+    return FALSE;
+}
+
+/* Utilities. */
+PUBLIC void st_cb_print(int level, char *msg, _magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    if (ST_CB_PRINT_LEVEL(level)) {
+        _magic_printf("[%s] %s. Current state element:\n",
+            ST_CB_LEVEL_TO_STR(level), msg);
+        MAGIC_SELEMENT_PRINT(selement, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+        MAGIC_SEL_ANALYZED_PRINT(sel_analyzed, MAGIC_EXPAND_TYPE_STR);
+        _magic_printf("\n");
+        MAGIC_SEL_STATS_PRINT(sel_stats);
+        _magic_printf("\n\n");
+    }
+}
+
+PUBLIC void st_cb_selement_type_cast(const struct _magic_type* new_selement_type, const struct _magic_type* new_local_selement_type, _magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    magic_selement_type_cast(selement, ST_SEL_ANALYZE_FLAGS,
+            new_selement_type, sel_analyzed, sel_stats);
+    if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) {
+        cb_info->local_selement->type = new_local_selement_type;
+    }
+}
+
+/* Stack management. */
+
+PUBLIC void st_stack_refs_save_restore(char* stack_buff, int is_save)
+{
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry* sentry;
+    struct st_stack_refs_buff *buff_ptr;
+    int i;
+
+#define __X(P) P
+    extern int ST_STACK_REFS_INT_LIST;
+#undef __X
+#define __X(P) ((int *)&(P))
+    int* int_ptrs[] = { ST_STACK_REFS_INT_LIST, ST_STACK_REFS_CUSTOM_LIST };
+#undef __X
+
+    assert((ST_STACK_REFS_NUM) == sizeof(int_ptrs)/sizeof(int_ptrs[0]));
+    assert(sizeof(int) == sizeof(void*));
+    buff_ptr = (struct st_stack_refs_buff*) stack_buff;
+
+    /* Save. */
+    if (is_save) {
+        buff_ptr->first_stack_dsentry = _magic_first_stack_dsentry;
+        buff_ptr->last_stack_dsentry = _magic_last_stack_dsentry;
+        if (_magic_first_stack_dsentry) {
+            buff_ptr->first_stack_obdsentry_buff = *MAGIC_OBDSENTRY_FROM_DSENTRY(_magic_first_stack_dsentry);
+        }
+        memcpy(buff_ptr->stack_range, magic_stack_range, 2*sizeof(void*));
+        for (i = 0 ; i < ST_STACK_REFS_NUM ; i++) {
+            memcpy(&buff_ptr->stack_int_refs[i], int_ptrs[i], sizeof(int));
+        }
+        return;
+    }
+
+    /* Restore. */
+    if (_magic_first_dsentry == _magic_last_stack_dsentry) {
+        _magic_first_dsentry = buff_ptr->last_stack_dsentry;
+    }
+    else {
+        MAGIC_DSENTRY_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
+            if (MAGIC_DSENTRY_HAS_NEXT(dsentry)
+                && MAGIC_DSENTRY_NEXT(dsentry) == _magic_last_stack_dsentry) {
+                MAGIC_DSENTRY_NEXT(dsentry) = buff_ptr->last_stack_dsentry;
+                break;
+            }
+        );
+    }
+
+    _magic_first_stack_dsentry = buff_ptr->first_stack_dsentry;
+    _magic_last_stack_dsentry = buff_ptr->last_stack_dsentry;
+    if (_magic_first_stack_dsentry) {
+        *MAGIC_OBDSENTRY_FROM_DSENTRY(_magic_first_stack_dsentry) = buff_ptr->first_stack_obdsentry_buff;
+    }
+    memcpy(magic_stack_range, buff_ptr->stack_range, 2*sizeof(void*));
+    for (i = 0 ; i < ST_STACK_REFS_NUM ; i++) {
+        memcpy(int_ptrs[i], &buff_ptr->stack_int_refs[i], sizeof(int));
+    }
+}
+
+/* Metadata management. */
+PUBLIC int st_add_special_mmapped_region(void *address, size_t size,
+    char* name)
+{
+    struct _magic_obdsentry* obdsentry;
+    char addr_name[24];
+
+    if (!_magic_enabled) return OK;
+
+    if (!name) {
+        sprintf(addr_name, "%%MMAP_0x%08x", (unsigned int) address);
+        name = addr_name;
+    }
+    obdsentry = magic_create_obdsentry(address, MAGIC_VOID_TYPE,
+        size, MAGIC_STATE_MAP, name, NULL);
+    return obdsentry ? OK : EINVAL;
+}
+
+PUBLIC int st_del_special_mmapped_region_by_addr(void *address)
+{
+    int ret;
+
+    if (!_magic_enabled) return OK;
+
+    ret = magic_destroy_obdsentry_by_addr(address);
+    if (ret < 0) {
+        return EINVAL;
+    }
+    return OK;
+}
+
+/* Selement transfer callbacks. */
+
+PRIVATE INLINE int transfer_walkable_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    /* Do nothing for complex type. process only its members, not the complex type itself */
+    return MAGIC_SENTRY_ANALYZE_CONTINUE;
+}
+
+PRIVATE INLINE int transfer_try_raw_copy_sel_cb(_magic_selement_t *selement, struct st_cb_info *cb_info)
+{
+    /* Only do raw copying if there are no type transformations. */
+    if ((selement->type->num_child_types == 0 && selement->type->size == cb_info->local_selement->type->size) || selement->type == cb_info->local_selement->type || ST_TYPE_IS_CACHED_COUNTERPART(selement->type, cb_info->local_selement->type)) {
+        memcpy(cb_info->local_selement->address, selement->address, cb_info->local_selement->type->size);
+        return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+    }
+
+    return MAGIC_SENTRY_ANALYZE_CONTINUE;
+}
+
+PRIVATE INLINE int transfer_identity_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) {
+        /* First try to do raw copying, assuming there are no type transformations. */
+        if (transfer_try_raw_copy_sel_cb(selement, cb_info) == MAGIC_SENTRY_ANALYZE_SKIP_PATH)
+            return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+
+#if CHECK_ASR && !FORCE_SOME_UNPAIRED_TYPES
+        if (cb_info->init_info->flags & ST_LU_ASR) {
+            st_cbs_os.panic("ASR should never get here!");
+        }
+#endif
+        if (selement->type->type_id == MAGIC_TYPE_UNION) {
+            ST_CB_PRINT(ST_CB_ERR, "uncaught ixfer union with type changes", selement, sel_analyzed, sel_stats, cb_info);
+            return EFAULT;
+        }
+        cb_info->st_cb_flags |= ST_CB_FORCE_IXFER;
+        return MAGIC_SENTRY_ANALYZE_CONTINUE;
+    }
+    return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+}
+
+PRIVATE INLINE int transfer_cond_identity_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    int r;
+    int saved_flags = cb_info->st_cb_flags;
+    cb_info->st_cb_flags &= ~ST_CB_PRINT_ERR;
+    r = default_transfer_selement_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    cb_info->st_cb_flags = saved_flags;
+    if (r < 0) {
+        ST_CB_PRINT(ST_CB_DBG, "conditional ixfer resorting to ixfer", selement, sel_analyzed, sel_stats, cb_info);
+        return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    }
+    return r;
+}
+
+PRIVATE INLINE int transfer_nonptr_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    if (sel_analyzed->flags & MAGIC_SEL_FOUND_VIOLATIONS) {
+        ST_CB_PRINT(ST_CB_ERR, "uncaught non-ptr with violations", selement, sel_analyzed, sel_stats, cb_info);
+        return EFAULT;
+    }
+    return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+}
+
+PRIVATE int transfer_ptr_sel_with_trg_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    int trg_flags, trg_extf_flags, trg_transferred, trg_paired;
+    _magic_selement_t cached_trg_selement, local_trg_selement;
+    void **local_selement_address = cb_info->local_selement->address;
+    int r;
+
+    r = lookup_trg_info(selement, sel_analyzed, sel_stats, cb_info, &cached_trg_selement, &local_trg_selement);
+    if (r != OK) {
+        return r;
+    }
+
+    trg_flags = sel_analyzed->u.ptr.trg_flags;
+    trg_extf_flags = MAGIC_STATE_FLAGS_TO_EXTF(trg_flags);
+    trg_transferred = (trg_extf_flags & (ST_NEEDS_TRANSFER | ST_TRANSFER_DONE));
+    trg_paired = (local_trg_selement.type != NULL);
+
+    if (!trg_transferred && trg_paired && (trg_extf_flags & ST_ON_PTRXFER_CASCADE)) {
+        /* Propagate transfer on the target. */
+        if (cached_trg_selement.sentry && !(trg_extf_flags & ST_NEEDS_TRANSFER)) {
+            ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in cascade transfer for the target", selement, sel_analyzed, sel_stats, cb_info);
+            st_set_status_by_sentry_id(ST_NEEDS_TRANSFER, ST_OP_ADD, MAGIC_SENTRY_ID(cached_trg_selement.sentry));
+        }
+        /* Force code below to transfer the pointer normally. */
+        trg_transferred = TRUE;
+    }
+
+    if (trg_transferred && trg_paired) {
+        *local_selement_address = local_trg_selement.address;
+    }
+    else if (trg_extf_flags & ST_ON_PTRXFER_SET_NULL) {
+        ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in forcefully setting ptr to NULL", selement, sel_analyzed, sel_stats, cb_info);
+        *local_selement_address = NULL;
+    }
+    else if(trg_extf_flags & ST_ON_PTRXFER_SET_DEFAULT) {
+        ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in forcefully setting ptr to default value", selement, sel_analyzed, sel_stats, cb_info);
+        if (trg_flags & MAGIC_STATE_STRING) {
+            *((char**)local_selement_address) = "";
+        }
+        else {
+            *local_selement_address = NULL;
+        }
+    }
+    else if (trg_extf_flags & ST_ON_PTRXFER_SKIP) {
+        ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in skipping ptr transfer", selement, sel_analyzed, sel_stats, cb_info);
+    }
+    else {
+        if (trg_paired) {
+            ST_CB_PRINT(ST_CB_ERR, "uncaught ptr lookup for non-transferred target", selement, sel_analyzed, sel_stats, cb_info);
+        }
+        else {
+            ST_CB_PRINT(ST_CB_ERR, "uncaught ptr lookup for unpaired target", selement, sel_analyzed, sel_stats, cb_info);
+        }
+#if DO_SKIP_UNPAIRED_PTR_TARGETS
+        return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+#else
+        return ENOENT;
+#endif
+    }
+
+    return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+}
+
+PRIVATE INLINE int transfer_ptr_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    const struct _magic_type *first_trg_type;
+    if (selement->type->type_id != MAGIC_TYPE_POINTER) {
+        if (selement->type->size != sizeof(void*)) {
+            ST_CB_PRINT(ST_CB_ERR, "wrong pointer size", selement, sel_analyzed, sel_stats, cb_info);
+            return EFAULT;
+        }
+        ST_CB_PRINT(ST_CB_DBG, "casting non-ptr to ptr element", selement, sel_analyzed, sel_stats, cb_info);
+        st_cb_selement_type_cast(MAGIC_VOID_PTR_INT_CAST_TYPE, MAGIC_VOID_PTR_INT_CAST_TYPE, selement, sel_analyzed, sel_stats, cb_info);
+    }
+    first_trg_type = MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(sel_analyzed);
+    if (first_trg_type == MAGIC_TYPE_NULL_ENTRY
+        || first_trg_type == MAGIC_TYPE_VALUE_FOUND) {
+
+        /* NULL pointer or special value. Don't adjust value */
+        return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+
+    } else if (!(sel_analyzed->flags & MAGIC_SEL_FOUND_VIOLATIONS)) {
+        /* Valid pointer found */
+        if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) {
+            return transfer_ptr_sel_with_trg_cb(selement, sel_analyzed, sel_stats, cb_info);
+        }
+
+        return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+
+    } else if(MAGIC_STATE_FLAG(selement->sentry, MAGIC_STATE_STACK)) {
+        struct _magic_sentry *trg_sentry = magic_sentry_lookup_by_range(sel_analyzed->u.ptr.value, NULL);
+        if (trg_sentry && !strcmp(trg_sentry->name, MAGIC_ALLOC_INITIAL_STACK_NAME)) {
+            /* Stack pointer to initial stack area. This is common (e.g., argv).
+             * We can safely assume the pointer will be already correctly
+             * initialized in the new version and simply skip transfer.
+             */
+            ST_CB_PRINT(ST_CB_DBG, "skipping stack ptr element pointing to initial stack area", selement, sel_analyzed, sel_stats, cb_info);
+            return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+        }
+    }
+
+    /* Pointer with violations found */
+    ST_CB_PRINT(ST_CB_ERR, "uncaught ptr with violations", selement, sel_analyzed, sel_stats, cb_info);
+#if DO_SKIP_INVARIANTS_VIOLATIONS
+    return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+#else
+    return EFAULT;
+#endif
+}
+
+PRIVATE INLINE int transfer_struct_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    static int st_counter = 0;
+    unsigned parent_offset, offset;
+    int walk_flags, ret;
+
+    if (selement->type->type_id != MAGIC_TYPE_UNION && selement->type->type_id != MAGIC_TYPE_STRUCT) {
+        ST_CB_PRINT(ST_CB_ERR, "struct transfer is only for structs and unions!", selement, sel_analyzed, sel_stats, cb_info);
+        return EFAULT;
+    }
+    if (selement->type->type_id == MAGIC_TYPE_STRUCT || st_counter > 0) {
+        return MAGIC_SENTRY_ANALYZE_CONTINUE;
+    }
+
+    /* Walk the union as a struct. */
+    walk_flags = cb_info->walk_flags;
+    cb_info->walk_flags = (MAGIC_TYPE_WALK_DEFAULT_FLAGS & (~MAGIC_TYPE_WALK_UNIONS_AS_VOID));
+    st_counter++;
+    parent_offset = (unsigned)selement->parent_address - (unsigned)selement->sentry->address;
+    offset = (unsigned)selement->address - (unsigned)selement->sentry->address;
+    ret =  magic_type_walk_flags(selement->parent_type, parent_offset,
+        selement->child_num, selement->type, offset,
+        0, ULONG_MAX, magic_type_analyzer_cb, selement->cb_args, cb_info->walk_flags);
+    st_counter--;
+    cb_info->walk_flags = walk_flags;
+    if (ret != 0) {
+        return ret == MAGIC_TYPE_WALK_STOP ? MAGIC_SENTRY_ANALYZE_STOP : ret;
+    }
+
+    return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+}
+
+PRIVATE INLINE int default_transfer_selement_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    /* Default handler for walkable, ptr and nonptr types. */
+#if ST_TRANSFER_IDENTITY_FOR_NO_INNER_PTRS
+    if (MAGIC_TYPE_FLAG(selement->type, MAGIC_TYPE_NO_INNER_PTRS)) {
+        /* If the type has no inner pointers, try to do raw copying. */
+        if (transfer_try_raw_copy_sel_cb(selement, cb_info) == MAGIC_SENTRY_ANALYZE_SKIP_PATH)
+            return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+    }
+#endif
+    if (selement->type->type_id == MAGIC_TYPE_UNION) {
+        if (!(st_policies & ST_IXFER_UNCAUGHT_UNIONS) && !MAGIC_TYPE_FLAG(selement->type, MAGIC_TYPE_NO_INNER_PTRS)) {
+            ST_CB_PRINT(ST_CB_ERR, "uncaught union", selement, sel_analyzed, sel_stats, cb_info);
+            return EFAULT;
+        }
+        else {
+            int level = (st_policies & ST_REPORT_UNCAUGHT_UNIONS) ? ST_CB_ERR : ST_CB_DBG;
+            ST_CB_PRINT(level, "uncaught union", selement, sel_analyzed, sel_stats, cb_info);
+            return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+        }
+    } else if (MAGIC_TYPE_IS_WALKABLE(selement->type)) {
+        return transfer_walkable_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    } else if (selement->type->type_id == MAGIC_TYPE_POINTER) {
+        return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    } else {
+        return transfer_nonptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    }
+
+    /* Not reachable. */
+    ST_CB_PRINT(ST_CB_ERR, "Bug!", selement, sel_analyzed, sel_stats, cb_info);
+    return EINTR;
+}
+
+PUBLIC int st_cb_transfer_sentry_default(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    char *sentry_name = selement->sentry->name;
+
+#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
+    if (MAGIC_STATE_FLAGS(selement->sentry, MAGIC_STATE_DYNAMIC)) {
+        if (MAGIC_STATE_FLAG(selement->sentry, MAGIC_STATE_LIB) || MAGIC_SENTRY_IS_EXT_ALLOC(selement->sentry))
+            return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+    }
+#endif
+
+    if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_ixfers, sentry_name)) {
+        ST_CB_PRINT(ST_CB_DBG, "sentry name matches ixfer", selement, sel_analyzed, sel_stats, cb_info);
+        return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    }
+
+    if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_cixfers, sentry_name)) {
+        ST_CB_PRINT(ST_CB_DBG, "sentry name matches cixfer", selement, sel_analyzed, sel_stats, cb_info);
+        return transfer_cond_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    }
+
+    if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_noxfers, sentry_name)) {
+        ST_CB_PRINT(ST_CB_DBG, "sentry name matches noxfer", selement, sel_analyzed, sel_stats, cb_info);
+        return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+    }
+
+    if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_pxfers, sentry_name)) {
+        ST_CB_PRINT(ST_CB_DBG, "sentry name matches pxfer", selement, sel_analyzed, sel_stats, cb_info);
+        return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    }
+
+    if (MAGIC_STATE_FLAGS(selement->sentry, MAGIC_STATE_DYNAMIC | MAGIC_STATE_MAP | MAGIC_STATE_LIB)) {
+        struct _magic_dsentry *dsentry = MAGIC_DSENTRY_FROM_SENTRY(selement->sentry);
+        if (ST_DSENTRY_PARENT_NAME_MATCH_ANY(st_dsentry_lib_noxfer, dsentry->parent_name)) {
+            ST_CB_PRINT(ST_CB_DBG, "dsentry is a lib map and parent_name matches dsentry_lib_noxfer", selement, sel_analyzed, sel_stats, cb_info);
+            return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+        }
+    }
+
+    return ST_CB_NOT_PROCESSED;
+}
+
+PUBLIC int st_cb_transfer_typename_default(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    char *typename_key = ST_TYPE_NAME_KEY(selement->type);
+    if (ST_TYPE_NAME_MATCH_ANY(st_typename_ixfers, typename_key)) {
+        return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    }
+
+    if (ST_TYPE_NAME_MATCH_ANY(st_typename_cixfers, typename_key)) {
+        return transfer_cond_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    }
+
+    if (ST_TYPE_NAME_MATCH_ANY(st_typename_noxfers, typename_key)) {
+        return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+    }
+
+    if (ST_TYPE_NAME_MATCH_ANY(st_typename_pxfers, typename_key)) {
+        return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    }
+
+    if (ST_TYPE_NAME_MATCH_ANY(st_typename_sxfers, typename_key)) {
+        return transfer_struct_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+    }
+
+    return ST_CB_NOT_PROCESSED;
+}
+
+PUBLIC int st_cb_transfer_walkable(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    return transfer_walkable_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+}
+
+PUBLIC int st_cb_transfer_ptr(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+}
+
+PUBLIC int st_cb_transfer_identity(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+}
+
+PUBLIC int st_cb_transfer_cond_identity(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    return transfer_cond_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+}
+
+PUBLIC int st_cb_transfer_nonptr(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    return transfer_nonptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+}
+
+PUBLIC int st_cb_transfer_struct(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    return transfer_struct_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+}
+
+PUBLIC int st_cb_transfer_selement_base(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    return default_transfer_selement_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+}
+
+PUBLIC int st_cb_transfer_selement_generic(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
+{
+    return transfer_data_selement(selement, sel_analyzed, sel_stats, cb_info);
+}
+
+/* Selement mapping functions and callbacks. */
+
+PRIVATE int st_map_selement_from_sentry_cb(const struct _magic_type* parent_type,
+    const unsigned parent_offset, int child_num,
+    const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
+{
+    void **args_array = (void**) cb_args;
+    _magic_selement_t cached_selement;
+    _magic_selement_t *local_selement = (_magic_selement_t*) args_array[1];
+    _magic_selement_t *selement = (_magic_selement_t*) args_array[0];
+    struct _magic_sentry *sentry = selement->sentry;
+    void *address = (char*)sentry->address + offset;
+    void *selement_address = selement->address;
+    int is_trg_mapping;
+    struct st_cb_info *cb_info;
+    if ((char*) selement_address >= ((char*) address + type->size)) {
+        return MAGIC_TYPE_WALK_SKIP_PATH;
+    }
+    cb_info = (struct st_cb_info*) args_array[2];
+    is_trg_mapping = (int) args_array[3];
+    cached_selement.sentry = sentry;
+    cached_selement.parent_type = parent_type;
+    cached_selement.parent_address = (char*)sentry->address + parent_offset;
+    cached_selement.child_num = child_num;
+    cached_selement.type = type;
+    cached_selement.address = address;
+    cached_selement.depth = depth;
+    st_map_selement(&cached_selement, local_selement, cb_info, is_trg_mapping);
+    if (local_selement->type == NULL) {
+        return ENOENT;
+    }
+    if (address == selement_address && type == selement->type) {
+        return MAGIC_TYPE_WALK_STOP;
+    }
+    if (type->num_child_types == 0) {
+        return EINVAL;
+    }
+    local_selement->parent_type = local_selement->type;
+    local_selement->parent_address = local_selement->address;
+    return MAGIC_TYPE_WALK_CONTINUE;
+}
+
+PRIVATE INLINE void st_map_selement_from_sentry(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct _magic_sentry *local_sentry, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    unsigned max_offset;
+    int r;
+    void *args_array[4];
+    max_offset = (unsigned) ( (char *)cached_selement->address - (char *)cached_selement->sentry->address);
+    args_array[0] = cached_selement;
+    args_array[1] = magic_selement_from_sentry(local_sentry, local_selement);
+    args_array[2] = cb_info;
+    args_array[3] = (void*) is_trg_mapping;
+    r = magic_type_walk_root(cached_selement->sentry->type, 0, max_offset, st_map_selement_from_sentry_cb, (void*) args_array);
+    if (r < 0) {
+        assert(r == ENOENT);
+        local_selement->type = NULL;
+    }
+}
+
+PRIVATE INLINE void st_map_sel_analyzed_from_target(_magic_sel_analyzed_t *cached_sel_analyzed, _magic_sel_analyzed_t *local_sel_analyzed, struct _magic_sentry *local_trg_sentry, struct _magic_function *local_trg_function, struct st_cb_info *cb_info)
+{
+    _magic_selement_t *csel, *lsel;
+    assert(local_trg_sentry || local_trg_function);
+    assert(cached_sel_analyzed->type_id == MAGIC_TYPE_POINTER);
+    assert(cached_sel_analyzed->u.ptr.first_legal_trg_type>=0);
+    local_sel_analyzed->type_id = cached_sel_analyzed->type_id;
+    local_sel_analyzed->num = cached_sel_analyzed->num;
+    local_sel_analyzed->flags = cached_sel_analyzed->flags;
+    local_sel_analyzed->u.ptr.trg_flags = local_trg_sentry ? local_trg_sentry->flags : local_trg_function->flags;
+    local_sel_analyzed->u.ptr.first_legal_trg_type = -1;
+    local_sel_analyzed->u.ptr.num_legal_trg_types = 0;
+    if (local_trg_function) {
+        assert(cached_sel_analyzed->u.ptr.num_legal_trg_types == 1);
+        lsel = &local_sel_analyzed->u.ptr.trg_selements[0];
+        memset(lsel, 0, sizeof(_magic_selement_t));
+        lsel->sentry = NULL;
+        lsel->type = local_trg_function->type;
+        lsel->address = local_trg_function->address;
+        local_sel_analyzed->u.ptr.num_trg_types = 1;
+    }
+    else {
+        int i;
+        void *address = NULL;
+        local_sel_analyzed->u.ptr.num_trg_types = 0;
+        for (i = cached_sel_analyzed->u.ptr.first_legal_trg_type ; i < cached_sel_analyzed->u.ptr.num_trg_types ; i++) {
+            _magic_trg_stats_t trg_stats = cached_sel_analyzed->u.ptr.trg_stats[i];
+            if (MAGIC_SEL_ANALYZED_TRG_STATS_HAS_VIOLATIONS(trg_stats)) {
+                continue;
+            }
+            csel = &cached_sel_analyzed->u.ptr.trg_selements[i];
+            lsel = &local_sel_analyzed->u.ptr.trg_selements[local_sel_analyzed->u.ptr.num_trg_types++];
+            st_map_selement_from_sentry(csel, lsel, local_trg_sentry, cb_info, TRUE);
+            if (lsel->type == NULL || (address && lsel->address != address)) {
+                /* Unpaired selement or ambiguous local address. */
+                local_sel_analyzed->u.ptr.num_trg_types = 0;
+                return;
+            }
+            address = lsel->address;
+        }
+        assert(local_sel_analyzed->u.ptr.num_trg_types > 0);
+    }
+}
+
+PUBLIC void st_map_local_selement_from_child_num(_magic_selement_t *local_selement, struct st_cb_info *cb_info, int child_num)
+{
+    local_selement->child_num = child_num;
+    magic_selement_fill_from_parent_info(local_selement, cb_info->walk_flags);
+}
+
+PUBLIC void st_cb_map_from_parent_array_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    int cached_num_elements, local_num_elements, is_trg_at_array_end, is_trg_at_str_end;
+    /* Match arrays/vectors with arrays/vectors. */
+    assert(cached_selement->parent_type->type_id == MAGIC_TYPE_ARRAY || cached_selement->parent_type->type_id == MAGIC_TYPE_VECTOR);
+    if (local_selement->parent_type->type_id != MAGIC_TYPE_ARRAY && local_selement->parent_type->type_id != MAGIC_TYPE_VECTOR) {
+        local_selement->type = NULL;
+        return;
+    }
+    cached_num_elements = cached_selement->parent_type->num_child_types;
+    local_num_elements = local_selement->parent_type->num_child_types;
+    /* Same size or first child? We are done. */
+    if (cached_num_elements == local_num_elements || local_selement->child_num == 0) {
+         st_map_local_selement_from_child_num(local_selement, cb_info, cached_selement->child_num);
+         return;
+    }
+    assert(local_num_elements > 0);
+    is_trg_at_str_end = FALSE;
+    is_trg_at_array_end = FALSE;
+    if (is_trg_mapping && cached_selement->child_num == cached_num_elements-1) {
+        is_trg_at_str_end = MAGIC_SENTRY_IS_STRING(cached_selement->sentry) || MAGIC_SENTRY_IS_STRING(local_selement->sentry);
+        is_trg_at_array_end = !is_trg_at_str_end;
+    }
+    if (is_trg_at_array_end && (st_policies & ST_DEFAULT_MAP_GUARD_PTRS_TO_ARRAY_END)) {
+        /* This should be interpreted as a target of a guard pointer pointing to the last element of an array and needs to be remapped as such. */
+        st_map_local_selement_from_child_num(local_selement, cb_info, local_num_elements-1);
+    }
+    else if (is_trg_at_str_end && (st_policies & ST_DEFAULT_MAP_GUARD_PTRS_TO_STR_END)) {
+        /* This should be interpreted as a target of a guard pointer pointing to the last element of a string and needs to be remapped as such. */
+        st_map_local_selement_from_child_num(local_selement, cb_info, local_num_elements-1);
+    }
+    else if (cached_selement->child_num >= local_num_elements) {
+        /* New array got truncated and this element is gone. */
+        local_selement->type = NULL;
+    }
+    else {
+        /* New array is bigger, just keep the original position in the array. */
+        st_map_local_selement_from_child_num(local_selement, cb_info, cached_selement->child_num);
+    }
+}
+
+PUBLIC void st_cb_map_child_array_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    size_t cached_size = cached_selement->type->num_child_types, local_size = local_selement->type->num_child_types;
+
+    /* Match arrays/vectors with arrays/vectors. */
+    assert(cached_selement->type->type_id == MAGIC_TYPE_ARRAY || cached_selement->type->type_id == MAGIC_TYPE_VECTOR);
+    if (local_selement->type->type_id != MAGIC_TYPE_ARRAY && local_selement->type->type_id != MAGIC_TYPE_VECTOR) {
+        local_selement->type = NULL;
+        return;
+    }
+
+    /* Varsized arrays have to be consistent across versions. */
+    if (MAGIC_TYPE_FLAG(cached_selement->type, MAGIC_TYPE_VARSIZE) != MAGIC_TYPE_FLAG(local_selement->type, MAGIC_TYPE_VARSIZE)) {
+        local_selement->type = NULL;
+        return;
+    }
+
+    /* Check size. */
+    if (cached_size != local_size) {
+        int report;
+        int is_string = MAGIC_SENTRY_IS_STRING(cached_selement->sentry) || MAGIC_SENTRY_IS_STRING(local_selement->sentry);
+        if (local_size < cached_size) {
+            report = is_string ? (st_policies & ST_REPORT_SMALLER_STRINGS) : (st_policies & ST_REPORT_SMALLER_ARRAYS);
+        }
+        else {
+            report = is_string ? (st_policies & ST_REPORT_LARGER_STRINGS) : (st_policies & ST_REPORT_LARGER_ARRAYS);
+        }
+
+        if (report) {
+            printf("st_cb_map_child_array_selement_generic: %s size found while mapping array selements:\n", local_size < cached_size ? "Smaller" : "Larger");
+            MAGIC_SELEMENT_PRINT(cached_selement, MAGIC_EXPAND_TYPE_STR); printf("\n");
+            MAGIC_SELEMENT_PRINT(local_selement, MAGIC_EXPAND_TYPE_STR); printf("\n");
+        }
+    }
+}
+
+PUBLIC void st_cb_map_from_parent_union_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    /* This should only be called in case of unions transferred as structs. */
+    st_cb_map_from_parent_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+}
+
+PUBLIC void st_cb_map_child_union_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    /* Match unions just like structs. */
+    st_cb_map_child_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+}
+
+PUBLIC void st_cb_map_from_parent_struct_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    int i;
+    char *cached_member_name;
+    /* Match struct/unions with struct/unions. */
+    assert(cached_selement->parent_type->type_id == MAGIC_TYPE_STRUCT || cached_selement->parent_type->type_id == MAGIC_TYPE_UNION);
+    if (local_selement->parent_type->type_id != MAGIC_TYPE_STRUCT && local_selement->parent_type->type_id != MAGIC_TYPE_UNION) {
+        local_selement->type = NULL;
+        return;
+    }
+    /* Match struct/unions members by name. */
+    cached_member_name = cached_selement->parent_type->member_names[cached_selement->child_num];
+    for (i = 0 ; i < local_selement->parent_type->num_child_types ; i++) {
+        if (!strcmp(local_selement->parent_type->member_names[i], cached_member_name)) {
+            st_map_local_selement_from_child_num(local_selement, cb_info, i);
+            return;
+        }
+    }
+    local_selement->type = NULL;
+}
+
+PUBLIC void st_cb_map_child_struct_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    int i, j;
+    const struct _magic_type *cached_type = cached_selement->type;
+    const struct _magic_type *local_type = local_selement->type;
+    assert(cached_type->type_id == MAGIC_TYPE_STRUCT || cached_type->type_id == MAGIC_TYPE_UNION);
+    if (local_type->type_id != MAGIC_TYPE_STRUCT && local_type->type_id != MAGIC_TYPE_UNION) {
+        local_selement->type = NULL;
+        return;
+    }
+    /* Match struct/unions by name(s). */
+    if (!strcmp(cached_type->name, local_type->name)) {
+        return;
+    }
+    if (cached_type->num_names > 1 || local_type->num_names > 1 ) {
+        for (i = 0 ; i < cached_type->num_names ; i++) {
+            for (j = 0 ; j < local_type->num_names ; j++) {
+                if (!strcmp(cached_type->names[i], local_type->names[j])) {
+                    return;
+                }
+            }
+        }
+    }
+
+    local_selement->type = NULL;
+}
+
+PUBLIC void st_cb_map_child_nonaggr_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    int r;
+    static char magic_value_buffer[32];
+
+    r = magic_selement_value_cast(cached_selement, local_selement, magic_value_buffer);
+    if (r == 0) {
+        return;
+    }
+    if (r < 0 && r != MAGIC_ERANGE && r != MAGIC_ESIGN) {
+        local_selement->type = NULL;
+        return;
+    }
+    if ((r == MAGIC_ERANGE && (st_policies & ST_REPORT_PRECISION_LOSS))
+        || (r == MAGIC_ESIGN && (st_policies & ST_REPORT_SIGN_CHANGE))) {
+        _magic_selement_t converted_selement = *cached_selement;
+        converted_selement.address = magic_value_buffer;
+        converted_selement.type = local_selement->type;
+        printf("st_cb_map_child_nonaggr_selement_generic: %s while mapping non-aggregate selements:\n", r == MAGIC_ERANGE ? "Precision loss" : "Sign change");
+        MAGIC_SELEMENT_PRINT(cached_selement, MAGIC_EXPAND_TYPE_STR); printf("\n");
+        MAGIC_SELEMENT_PRINT(local_selement, MAGIC_EXPAND_TYPE_STR); printf("\n");
+        printf(" - ORIGINAL VALUE: "); magic_selement_print_value(cached_selement); printf("\n");
+        printf(" - MAPPED   VALUE: "); magic_selement_print_value(&converted_selement); printf("\n");
+    }
+    cached_selement->address = magic_value_buffer;
+}
+
+PUBLIC void st_cb_map_from_parent_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    assert(cached_selement->parent_type && local_selement->parent_type);
+    switch(cached_selement->parent_type->type_id) {
+        case MAGIC_TYPE_ARRAY:
+        case MAGIC_TYPE_VECTOR:
+             st_cb_map_from_parent_array_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+        break;
+
+        case MAGIC_TYPE_UNION:
+            st_cb_map_from_parent_union_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+        break;
+
+        case MAGIC_TYPE_STRUCT:
+            st_cb_map_from_parent_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+        break;
+
+        default:
+            st_cbs_os.panic("Invalid parent type!");
+        break;
+    }
+}
+
+PUBLIC void st_cb_map_child_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    assert(cached_selement->type);
+    if (local_selement->type == NULL) {
+        return;
+    }
+    if (cached_selement->type->num_child_types == 0 || cached_selement->type->type_id == MAGIC_TYPE_POINTER) {
+        st_cb_map_child_nonaggr_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+        return;
+    }
+    switch (cached_selement->type->type_id) {
+        case MAGIC_TYPE_ARRAY:
+        case MAGIC_TYPE_VECTOR:
+            st_cb_map_child_array_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+        break;
+
+        case MAGIC_TYPE_UNION:
+            st_cb_map_child_union_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+        break;
+
+        case MAGIC_TYPE_STRUCT:
+            st_cb_map_child_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+        break;
+
+        default:
+            st_cbs_os.panic("Invalid parent type!");
+        break;
+    }
+}
+
+
+PUBLIC void st_cb_map_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    int i;
+    assert(cached_selement->type->type_id != MAGIC_TYPE_FUNCTION);
+    for (i = 0 ; i < MAGIC_ST_TYPE_TRANS_ITERATIONS ; i++) {
+        if (cached_selement->parent_type) {
+            st_cb_map_from_parent_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+        }
+        st_cb_map_child_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
+    }
+}
+
+PRIVATE INLINE void st_map_selement(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
+{
+    const struct _magic_type *cached_parent_type = cached_selement->parent_type;
+    const struct _magic_type *local_parent_type = local_selement->parent_type;
+    const struct _magic_type *cached_type = cached_selement->type;
+
+    if (cached_parent_type) {
+        if (cached_parent_type == local_parent_type) {
+            /* Quickly propagate perfect type pairs from parents. */
+            local_selement->address = (char *)local_selement->parent_address + ((char *)cached_selement->address - (char *)cached_selement->parent_address);
+            local_selement->type = cached_type;
+            return;
+        }
+        else if (ST_TYPE_IS_CACHED_COUNTERPART(cached_parent_type, local_parent_type)) {
+            /* Quickly propagate type pairs from parents. */
+            st_map_local_selement_from_child_num(local_selement, cb_info, cached_selement->child_num);
+            return;
+        }
+        else {
+            local_selement->type = NULL;
+        }
+    }
+    else {
+        /* In case of target mapping, we don't care about compatible types. When paired types are found, add a perfect type pair to speed up subsequent lookups. */
+        if (ST_TYPE_IS_CACHED_COUNTERPART(cached_type, local_selement->type)) {
+            if (is_trg_mapping) local_selement->type = cached_type;
+            return;
+        }
+    }
+#if CHECK_ASR && !FORCE_SOME_UNPAIRED_TYPES
+    if (cb_info->init_info->flags & ST_LU_ASR) {
+        st_cbs_os.panic("ASR should never get here!");
+    }
+#endif
+
+    st_num_type_transformations++;
+    st_cbs.st_cb_selement_map(cached_selement, local_selement, cb_info, is_trg_mapping);
+
+    /* Check again for paired types and add a perfect type pair to speed up subsequent lookups in case of target mapping. */
+    if (is_trg_mapping && local_selement->type != NULL && local_selement->type != cached_selement->type) {
+        if (ST_TYPE_IS_CACHED_COUNTERPART(cached_selement->type, local_selement->type)) {
+            local_selement->type = cached_selement->type;
+        }
+    }
+}
+
+/* main functions */
+
+PUBLIC int st_state_transfer(st_init_info_t *info)
+{
+    int r;
+
+    /*
+     * Set all OS dependent callbacks first.
+     */
+    st_setcb_os_all(&info->st_cbs_os);
+
+#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
+    _magic_vars->fake_malloc = 1;
+#endif
+
+    r = st_init(info);
+
+#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
+    _magic_vars->fake_malloc = 0;
+#endif
+
+    if (r != OK) {
+        return r;
+    }
+
+    r = st_data_transfer(info);
+    if (r != OK) {
+        return r;
+    }
+
+#if ST_DEBUG_LEVEL > 0
+    printf("st_state_transfer: state transfer is done, num type transformations: %u.\n", st_num_type_transformations);
+#endif
+
+    st_cleanup(info);
+
+    return OK;
+}
+
+PUBLIC void st_set_policies(int policies)
+{
+    st_policies = policies;
+}
+
+#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
+PRIVATE void st_init_rl_index(st_init_info_t *info,
+    struct _magic_vars_t *magic_vars)
+{
+    size_t buff_size;
+    void *buff;
+
+    EXEC_WITH_MAGIC_VARS(
+        buff_size = magic_sentry_rl_estimate_index_buff_size(0);
+        , magic_vars
+    );
+    buff = st_buff_allocate(info, buff_size);
+
+    EXEC_WITH_MAGIC_VARS(
+        magic_sentry_rl_build_index(buff, buff_size);
+        , magic_vars
+    );
+}
+
+PRIVATE void st_cleanup_rl_index(st_init_info_t *info,
+    struct _magic_vars_t *magic_vars)
+{
+    EXEC_WITH_MAGIC_VARS(
+        magic_sentry_rl_destroy_index();
+        , magic_vars
+    );
+}
+#endif
+
+#if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH
+PRIVATE void st_init_sentry_hash(st_init_info_t *info,
+    struct _magic_vars_t *magic_vars)
+{
+    size_t buff_size;
+    void *buff;
+
+    EXEC_WITH_MAGIC_VARS(
+        buff_size = magic_sentry_hash_estimate_buff_size(0);
+        , magic_vars
+    );
+    buff = st_buff_allocate(info, buff_size);
+
+    EXEC_WITH_MAGIC_VARS(
+        magic_sentry_hash_build(buff, buff_size);
+        , magic_vars
+    );
+}
+
+PRIVATE void st_cleanup_sentry_hash(st_init_info_t *info,
+    struct _magic_vars_t *magic_vars)
+{
+    EXEC_WITH_MAGIC_VARS(
+        magic_sentry_hash_destroy();
+        , magic_vars
+    );
+}
+#endif
+
+#if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH
+PRIVATE void st_init_function_hash(st_init_info_t *info,
+    struct _magic_vars_t *magic_vars)
+{
+    size_t buff_size;
+    void *buff;
+
+    EXEC_WITH_MAGIC_VARS(
+        buff_size = magic_function_hash_estimate_buff_size(0);
+        , magic_vars
+    );
+    buff = st_buff_allocate(info, buff_size);
+
+    EXEC_WITH_MAGIC_VARS(
+        magic_function_hash_build(buff, buff_size);
+        , magic_vars
+    );
+}
+
+PRIVATE void st_cleanup_function_hash(st_init_info_t *info,
+    struct _magic_vars_t *magic_vars)
+{
+    EXEC_WITH_MAGIC_VARS(
+        magic_function_hash_destroy();
+        , magic_vars
+    );
+}
+#endif
+
+PRIVATE void st_vars_clear_ptrs(struct _magic_vars_t *magic_vars)
+{
+#undef __X
+#define __X(x) offsetof(struct _magic_vars_t, x)
+    size_t offset_list[] = { ST_MAGIC_VARS_PTR_CLEAR_LIST };
+#undef __X
+    int i;
+
+    for (i = 0 ; i < sizeof(offset_list) / sizeof(size_t) ; i++)
+        *((void **)(((char *)magic_vars) + offset_list[i])) = NULL;
+}
+
+PUBLIC int st_init(st_init_info_t *info)
+{
+    int r, max_buff_sz = 0, dsentries_num;
+    int allow_unpaired_types = TRUE;
+    if (st_init_done) {
+        return OK;
+    }
+    if (!_magic_enabled) return ENOSYS;
+    st_init_done = TRUE;
+
+    /* Ignore nested mempool dsentries for now. */
+    magic_lookup_nested_dsentries = 0;
+
+    /* Override default state transfer policies for ASR. */
+    if ((info->flags & ST_LU_ASR) && st_policies == ST_POLICIES_DEFAULT) {
+        st_policies = ST_POLICIES_DEFAULT_TRANSFER_ASR;
+    }
+
+    /* Fixup state transfer policies based on current configuration. */
+#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
+    st_policies &= (~ST_DEFAULT_ALLOC_CASCADE_XFER);
+#elif !defined(__MINIX)
+    st_policies |= ST_TRANSFER_DIRTY_ONLY;
+#endif
+
+    assert((!info->init_buff_start || (info->flags & ST_LU_NOMMAP)) && "st_init: no mmapping allowed, and no buffer is available");
+    register_typenames_and_callbacks();
+
+    /* Transfer _magic_vars, which contain addresses of the magic variables */
+    r = st_cbs_os.old_state_table_lookup(info->info_opaque, &st_remote_magic_vars);
+    assert( r == OK && "ERROR occurred during transfer of _magic_vars.");
+    /*
+     * Clear all pointers not explictly transferred, as they are not valid in
+     * the new address space.
+     */
+    st_vars_clear_ptrs(&st_remote_magic_vars);
+
+    /*
+     * Some magic_vars members do not need transfer or adjustment
+     * (e.g. the memory ranges). They are copied to st_cached_magic_vars
+     * this way.
+     */
+    st_cached_magic_vars = st_remote_magic_vars;
+
+    /* Transfer and adjust metadata */
+    r = st_transfer_metadata_types(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts);
+    assert( r == OK && "ERROR occurred during transfer of type metadata.");
+    r = transfer_metadata_functions(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts);
+    assert( r == OK && "ERROR occurred during transfer of function metadata.");
+    r = transfer_metadata_dfunctions(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts);
+    assert( r == OK && "ERROR occurred during transfer of dfunction metadata.");
+    r = transfer_metadata_sentries(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts, &max_buff_sz);
+    assert( r == OK && "ERROR occurred during transfer of sentry metadata.");
+    r = st_transfer_metadata_dsentries(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts, &max_buff_sz, &dsentries_num);
+    assert( r == OK && "ERROR occurred during transfer of dsentry metadata.");
+
+    /* Allocate buffer for data transfer */
+    st_dsentry_buff = st_buff_allocate(info, max_buff_sz + sizeof(struct _magic_dsentry));
+    if (!st_dsentry_buff) {
+        printf("st_dsentry_buff could not be allocated.\n");
+        return EGENERIC;
+    }
+    st_data_buff = &st_dsentry_buff[1];
+
+    /* Allocate and initialize counterparts buffers. */
+    st_counterparts.functions_size = st_cached_magic_vars.functions_num;
+    st_counterparts.functions = st_buff_allocate(info, st_counterparts.functions_size * sizeof(st_ptr_mapping));
+    assert(st_counterparts.functions && "st_counterparts.functions could not be allocated.");
+
+    st_counterparts.types_size = st_cached_magic_vars.types_num;
+    st_counterparts.types = st_buff_allocate(info, st_counterparts.types_size * sizeof(st_ptr_mapping));
+    assert(st_counterparts.types && "st_counterparts.types could not be allocated.");
+    st_counterparts.ptr_types = st_buff_allocate(info, st_counterparts.types_size * sizeof(st_ptr_mapping));
+    assert(st_counterparts.ptr_types && "st_counterparts.ptr_types could not be allocated.");
+
+    st_counterparts.sentries_size = st_cached_magic_vars.sentries_num + dsentries_num;
+    st_counterparts.sentries = st_buff_allocate(info, st_counterparts.sentries_size * sizeof(st_ptr_mapping));
+    assert(st_counterparts.sentries && "st_counterparts.sentries could not be allocated.");
+    st_counterparts.sentries_data = st_buff_allocate(info, st_counterparts.sentries_size * sizeof(st_ptr_mapping));
+    assert(st_counterparts.sentries_data && "st_counterparts.sentries_data could not be allocated.");
+
+#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
+    st_init_rl_index(info, &st_cached_magic_vars);
+#endif
+
+#if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH
+    st_init_sentry_hash(info, &st_cached_magic_vars);
+    st_init_sentry_hash(info, _magic_vars);
+#endif
+
+#if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH
+    st_init_function_hash(info, &st_cached_magic_vars);
+    st_init_function_hash(info, _magic_vars);
+#endif
+
+    /* Pair metadata entities */
+    r = pair_metadata_types(info, &st_cached_magic_vars, &st_counterparts, allow_unpaired_types);
+    assert( r == OK && "ERROR occurred during call to pair_metadata_types().");
+    r = pair_metadata_functions(info, &st_cached_magic_vars, &st_counterparts);
+    assert( r == OK && "ERROR occurred during call to pair_metadata_functions().");
+    r = pair_metadata_sentries(info, &st_cached_magic_vars, &st_counterparts);
+    assert( r == OK && "ERROR occurred during call to pair_metadata_sentries().");
+#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
+    r = allocate_pair_metadata_dsentries_from_raw_copy(info, &st_cached_magic_vars, &st_counterparts);
+    assert( r == OK && "ERROR occurred during call to allocate_pair_metadata_dsentries().");
+#else
+    r = allocate_pair_metadata_dsentries(info, &st_cached_magic_vars, &st_counterparts);
+    assert( r == OK && "ERROR occurred during call to allocate_pair_metadata_dsentries().");
+#endif
+
+    /* Set state transfer status defaults from the predefined policies. */
+    st_set_status_defaults(info);
+
+#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
+    st_init_rl_index(info, _magic_vars);
+#endif
+
+    return OK;
+}
+
+PRIVATE INLINE char* st_lookup_str_local_data(struct _magic_sentry *cached_sentry)
+{
+    void *local_data_addr;
+    assert(cached_sentry && MAGIC_SENTRY_IS_STRING(cached_sentry));
+    ST_GET_CACHED_COUNTERPART(cached_sentry, sentries, sentries_data, local_data_addr);
+    assert(local_data_addr && "String data not in cache!");
+    return (char*) local_data_addr;
+}
+
+#if ST_DEBUG_DATA_TRANSFER
+PRIVATE void st_print_sentities(struct _magic_vars_t *magic_vars)
+{
+    struct _magic_dsentry *dsentry = magic_vars->first_dsentry;
+    int i;
+
+    for (i = 0 ; i < magic_vars->sentries_num ; i++) {
+        struct _magic_sentry *sentry = &magic_vars->sentries[i];
+        ST_SENTRY_PRINT(sentry, 0);
+        printf("\n");
+    }
+
+    while (dsentry != NULL) {
+        ST_DSENTRY_PRINT(dsentry, 0);
+        printf("\n");
+        dsentry = dsentry->next;
+    }
+
+    for (i = 0 ; i < magic_vars->functions_num ; i++) {
+        struct _magic_function *function = &magic_vars->functions[i];
+        ST_FUNCTION_PRINT(function, 0);
+        printf("\n");
+    }
+}
+#endif
+
+PUBLIC void st_map_str_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr)
+{
+    struct _magic_sentry *cached_sentry = *cached_sentry_ptr;
+    struct _magic_sentry *local_sentry = *local_sentry_ptr;
+    struct _magic_sentry *sentry = cached_sentry ? cached_sentry : local_sentry;
+    int string_flags, match_by_name, match_by_content;
+    ST_CHECK_INIT();
+    assert((cached_sentry == NULL) ^ (local_sentry == NULL));
+
+    string_flags = sentry->flags & (MAGIC_STATE_STRING|MAGIC_STATE_NAMED_STRING);
+    assert(string_flags & MAGIC_STATE_STRING);
+    match_by_name = (string_flags & MAGIC_STATE_NAMED_STRING) && (st_policies & ST_MAP_NAMED_STRINGS_BY_NAME);
+    match_by_content = ((string_flags & MAGIC_STATE_NAMED_STRING) && (st_policies & ST_MAP_NAMED_STRINGS_BY_CONTENT))
+        || (!(string_flags & MAGIC_STATE_NAMED_STRING) && (st_policies & ST_MAP_STRINGS_BY_CONTENT));
+    if (match_by_name) {
+        /* Pretend it's a regular sentry and match by name */
+        sentry->flags &= ~string_flags;
+        st_map_sentries(cached_sentry_ptr, local_sentry_ptr);
+        sentry->flags |= string_flags;
+        if (*cached_sentry_ptr && *local_sentry_ptr) {
+            /* Found by name. */
+            return;
+        }
+    }
+    if (!match_by_content) {
+        /* No match. */
+        return;
+    }
+    if (cached_sentry) {
+        EXEC_WITH_MAGIC_VARS(
+            local_sentry = magic_sentry_lookup_by_string(st_lookup_str_local_data(cached_sentry));
+            , st_local_magic_vars_ptr
+        );
+    }
+    else {
+        int i;
+        for(i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) {
+            struct _magic_sentry *sentry = &st_cached_magic_vars.sentries[i];
+            if (MAGIC_SENTRY_IS_STRING(sentry) && !strcmp(st_lookup_str_local_data(sentry), (char*)local_sentry->address)) {
+                cached_sentry = sentry;
+                break;
+            }
+        }
+    }
+    *cached_sentry_ptr = cached_sentry;
+    *local_sentry_ptr = local_sentry;
+}
+
+PUBLIC void st_map_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr)
+{
+    struct _magic_sentry *cached_sentry = *cached_sentry_ptr;
+    struct _magic_sentry *local_sentry = *local_sentry_ptr;
+    struct _magic_dsentry *cached_dsentry = cached_sentry ? (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC) ? MAGIC_DSENTRY_FROM_SENTRY(cached_sentry) : NULL) : NULL;
+    struct _magic_dsentry *local_dsentry = local_sentry ? (MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC) ? MAGIC_DSENTRY_FROM_SENTRY(local_sentry) : NULL) : NULL;
+    ST_CHECK_INIT();
+    assert((cached_sentry == NULL) ^ (local_sentry == NULL));
+
+    if ((cached_sentry && MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_STRING))
+        || (local_sentry && MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_STRING))) {
+            st_map_str_sentries(cached_sentry_ptr, local_sentry_ptr);
+            return;
+    }
+    else if (cached_sentry) {
+        EXEC_WITH_MAGIC_VARS(
+            local_sentry = magic_sentry_lookup_by_name(cached_dsentry ? cached_dsentry->parent_name : "", cached_sentry->name, cached_dsentry ? cached_dsentry->site_id : 0, NULL);
+            , st_local_magic_vars_ptr
+        );
+        assert(!local_sentry || MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC) == MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC));
+    }
+    else {
+        EXEC_WITH_MAGIC_VARS(
+            cached_sentry = magic_sentry_lookup_by_name(local_dsentry ? local_dsentry->parent_name : "", local_sentry->name, local_dsentry ? local_dsentry->site_id : 0, NULL);
+            , &st_cached_magic_vars
+        );
+        assert(!cached_sentry || MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC) == MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC));
+    }
+    *cached_sentry_ptr = cached_sentry;
+    *local_sentry_ptr = local_sentry;
+}
+
+PRIVATE struct _magic_sentry *st_lookup_cached_sentry(struct _magic_sentry *local_sentry)
+{
+    int i;
+    struct _magic_dsentry *cached_dsentry;
+    assert(local_sentry);
+
+    for (i = 0 ; i < st_counterparts.sentries_size ; i++) {
+        if (st_counterparts.sentries[i].counterpart == local_sentry) {
+            break;
+        }
+    }
+    if (i >= st_counterparts.sentries_size) {
+        return NULL;
+    }
+    if (i < st_cached_magic_vars.sentries_num) {
+        return &st_cached_magic_vars.sentries[i];
+    }
+    i -= st_cached_magic_vars.sentries_num;
+    cached_dsentry = st_cached_magic_vars.first_dsentry;
+    assert(i >= 0);
+    assert(cached_dsentry);
+    while (i > 0) {
+        cached_dsentry = cached_dsentry->next;
+        assert(cached_dsentry);
+        i--;
+    }
+    return MAGIC_DSENTRY_TO_SENTRY(cached_dsentry);
+}
+
+PUBLIC void st_lookup_sentry_pair(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr)
+{
+    struct _magic_sentry *cached_sentry = *cached_sentry_ptr;
+    struct _magic_sentry *local_sentry = *local_sentry_ptr;
+    ST_CHECK_INIT();
+    assert((cached_sentry == NULL) ^ (local_sentry == NULL));
+
+    if (cached_sentry) {
+        ST_GET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry);
+    }
+    else if (MAGIC_SENTRY_IS_STRING(local_sentry)) {
+        /* strings are special, they may have multiple local duplicates */
+        struct _magic_sentry *csentry = NULL, *lsentry = NULL;
+        st_map_str_sentries(&csentry, &local_sentry);
+        if (csentry) {
+            st_lookup_sentry_pair(&csentry, &lsentry);
+            if (lsentry) {
+                cached_sentry = csentry;
+            }
+        }
+    }
+    else {
+        cached_sentry = st_lookup_cached_sentry(local_sentry);
+    }
+    *cached_sentry_ptr = cached_sentry;
+    *local_sentry_ptr = local_sentry;
+}
+
+PRIVATE INLINE void st_unpair_local_alloc_sentry(struct _magic_sentry *local_sentry)
+{
+    if (st_policies & ST_ON_ALLOC_UNPAIR_ERROR) {
+        st_cbs_os.panic("st_unpair_local_alloc_sentry: Error: attempting to unpair a local alloc sentry!");
+    }
+    else if (st_policies & ST_ON_ALLOC_UNPAIR_DEALLOCATE) {
+        deallocate_local_dsentry(MAGIC_DSENTRY_FROM_SENTRY(local_sentry));
+    }
+}
+
+PUBLIC void st_add_sentry_pair(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry)
+{
+    ST_CHECK_INIT();
+    assert(cached_sentry || local_sentry);
+
+    if (local_sentry) {
+        struct _magic_sentry *csentry = NULL;
+        st_lookup_sentry_pair(&csentry, &local_sentry);
+        if (csentry) {
+            ST_SET_CACHED_COUNTERPART(csentry, sentries, sentries, NULL);
+        }
+        if (!cached_sentry && MAGIC_SENTRY_IS_ALLOC(local_sentry)) {
+            st_unpair_local_alloc_sentry(local_sentry);
+        }
+    }
+    if (cached_sentry) {
+        struct _magic_sentry *lsentry = NULL;
+        st_lookup_sentry_pair(&cached_sentry, &lsentry);
+        if (lsentry && MAGIC_SENTRY_IS_ALLOC(lsentry)) {
+            st_unpair_local_alloc_sentry(lsentry);
+        }
+        ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry);
+    }
+}
+
+PUBLIC int st_add_sentry_pair_alloc_by_dsindex(st_init_info_t *info, struct _magic_sentry *cached_sentry, struct _magic_dsindex *local_dsindex, int num_elements, const union __alloc_flags *p_alloc_flags)
+{
+    int r;
+    struct _magic_dsentry *local_dsentry;
+    ST_CHECK_INIT();
+    assert(cached_sentry);
+
+    if (!local_dsindex) {
+        st_add_sentry_pair(cached_sentry, NULL);
+        return OK;
+    }
+
+    r = allocate_local_dsentry(info, local_dsindex, num_elements, MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_TYPE_SIZE_MISMATCH), p_alloc_flags, &local_dsentry, NULL, MAGIC_PTR_TO_DSENTRY(cached_sentry->address));
+    if (r != OK) {
+        return r;
+    }
+    st_add_sentry_pair(cached_sentry, MAGIC_DSENTRY_TO_SENTRY(local_dsentry));
+    return OK;
+}
+
+PUBLIC void st_map_functions(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr)
+{
+    struct _magic_function *cached_function = *cached_function_ptr;
+    struct _magic_function *local_function = *local_function_ptr;
+    ST_CHECK_INIT();
+    assert((cached_function == NULL) ^ (local_function == NULL));
+
+    if (cached_function) {
+        EXEC_WITH_MAGIC_VARS(
+            local_function = magic_function_lookup_by_name(NULL, cached_function->name);
+            , st_local_magic_vars_ptr
+        );
+    }
+    else {
+        EXEC_WITH_MAGIC_VARS(
+            cached_function = magic_function_lookup_by_name(NULL, local_function->name);
+            , &st_cached_magic_vars
+        );
+    }
+    *cached_function_ptr = cached_function;
+    *local_function_ptr = local_function;
+}
+
+PUBLIC void st_lookup_function_pair(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr)
+{
+    struct _magic_function *cached_function = *cached_function_ptr;
+    struct _magic_function *local_function = *local_function_ptr;
+    int i;
+    ST_CHECK_INIT();
+    assert((cached_function == NULL) ^ (local_function == NULL));
+
+    if (cached_function) {
+        if (cached_function->id - 1 >= st_counterparts.functions_size) {
+            /*
+             * Try to check if this is a function
+             * from an external shared object.
+             * XXX: The number of dfunctions can be quite large,
+             * so this needs to be done more efficiently.
+             */
+            struct _magic_dfunction *dfunc;
+            struct _magic_function *func;
+            MAGIC_DFUNCTION_FUNC_ITER(_magic_vars->first_dfunction, dfunc, func,
+                if (func->address == cached_function->address) {
+                    local_function = func;
+                    break;
+                }
+            );
+            assert(local_function != NULL && "No counterpart found for function.");
+        } else {
+            ST_GET_CACHED_COUNTERPART(cached_function, functions, functions, local_function);
+        }
+    }
+    else {
+        assert(st_counterparts.functions_size == st_cached_magic_vars.functions_num);
+        for(i = 0 ; i < st_counterparts.functions_size ; i++) {
+            if(st_counterparts.functions[i].counterpart == local_function) {
+                cached_function = &st_cached_magic_vars.functions[i];
+                break;
+            }
+        }
+    }
+    *cached_function_ptr = cached_function;
+    *local_function_ptr = local_function;
+}
+
+PUBLIC void st_add_function_pair(struct _magic_function *cached_function, struct _magic_function *local_function)
+{
+    ST_CHECK_INIT();
+    assert(cached_function || local_function);
+
+    if (local_function) {
+        struct _magic_function *cfunction = NULL;
+        st_lookup_function_pair(&cfunction, &local_function);
+        if (cfunction) {
+            ST_SET_CACHED_COUNTERPART(cfunction, functions, functions, NULL);
+        }
+    }
+    if (cached_function) {
+        ST_SET_CACHED_COUNTERPART(cached_function, functions, functions, local_function);
+    }
+}
+
+PUBLIC int st_sentry_equals(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry)
+{
+    char *cached_parent_name = "", *local_parent_name = "";
+    int cached_flags = MAGIC_STATE_FLAGS_TO_NONEXTF(cached_sentry->flags) & (~MAGIC_STATE_ADDR_NOT_TAKEN);
+    int local_flags = MAGIC_STATE_FLAGS_TO_NONEXTF(local_sentry->flags) & (~MAGIC_STATE_ADDR_NOT_TAKEN);
+    if (cached_flags != local_flags) {
+        return FALSE;
+    }
+    if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_STRING)) {
+        return !strcmp(st_lookup_str_local_data(cached_sentry), (char*)local_sentry->address);
+    }
+    if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)) {
+        cached_parent_name = MAGIC_DSENTRY_FROM_SENTRY(cached_sentry)->parent_name;
+        local_parent_name = MAGIC_DSENTRY_FROM_SENTRY(local_sentry)->parent_name;
+    }
+    if (strcmp(cached_sentry->name, local_sentry->name) || strcmp(cached_parent_name, local_parent_name)) {
+        return FALSE;
+    }
+    return magic_type_compatible(cached_sentry->type, local_sentry->type, MAGIC_TYPE_COMPARE_ALL);
+}
+
+PUBLIC int st_function_equals(struct _magic_function *cached_function, struct _magic_function *local_function)
+{
+    if (MAGIC_STATE_FLAGS_TO_NONEXTF(local_function->flags) != MAGIC_STATE_FLAGS_TO_NONEXTF(cached_function->flags)) {
+        return FALSE;
+    }
+    return !strcmp(cached_function->name, local_function->name);
+}
+
+PUBLIC void st_print_sentry_diff(st_init_info_t *info, struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry, int raw_diff, int print_changed)
+{
+    int is_paired_sentry;
+    ST_CHECK_INIT();
+
+    if (!cached_sentry || !local_sentry) {
+        if (raw_diff) {
+            st_map_sentries(&cached_sentry, &local_sentry);
+        }
+        else {
+            st_lookup_sentry_pair(&cached_sentry, &local_sentry);
+        }
+    }
+    is_paired_sentry = (cached_sentry != NULL && local_sentry != NULL);
+    if (is_paired_sentry && st_sentry_equals(cached_sentry, local_sentry)) {
+        return;
+    }
+    if (is_paired_sentry && !print_changed) {
+        return;
+    }
+    if (cached_sentry) {
+        printf("-"); ST_SENTRY_PRINT(cached_sentry, MAGIC_EXPAND_TYPE_STR); printf("\n");
+    }
+    if (local_sentry) {
+        printf("+"); ST_SENTRY_PRINT(local_sentry, MAGIC_EXPAND_TYPE_STR); printf("\n");
+    }
+    printf("\n");
+}
+
+PUBLIC void st_print_function_diff(st_init_info_t *info, struct _magic_function *cached_function, struct _magic_function *local_function, int raw_diff, int print_changed)
+{
+    int is_paired_function;
+    ST_CHECK_INIT();
+
+    if (!cached_function || !local_function) {
+        if (raw_diff) {
+            st_map_functions(&cached_function, &local_function);
+        }
+        else {
+            st_lookup_function_pair(&cached_function, &local_function);
+        }
+    }
+    is_paired_function = (cached_function != NULL && local_function != NULL);
+    if (is_paired_function && st_function_equals(cached_function, local_function)) {
+        return;
+    }
+    if (is_paired_function && !print_changed) {
+        return;
+    }
+    if (cached_function) {
+        printf("-"); ST_FUNCTION_PRINT(cached_function, MAGIC_EXPAND_TYPE_STR); printf("\n");
+    }
+    if (local_function) {
+        printf("+"); ST_FUNCTION_PRINT(local_function, MAGIC_EXPAND_TYPE_STR); printf("\n");
+    }
+    printf("\n");
+}
+
+PUBLIC void st_print_sentries_diff(st_init_info_t *info, int raw_diff, int print_changed)
+{
+    int i;
+    ST_CHECK_INIT();
+
+    for (i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) {
+        struct _magic_sentry *cached_sentry = &st_cached_magic_vars.sentries[i];
+        st_print_sentry_diff(info, cached_sentry, NULL, raw_diff, print_changed);
+    }
+
+    print_changed = FALSE;
+    for (i = 0 ; i < st_local_magic_vars_ptr->sentries_num ; i++) {
+        struct _magic_sentry *local_sentry = &st_local_magic_vars_ptr->sentries[i];
+        st_print_sentry_diff(info, NULL, local_sentry, raw_diff, print_changed);
+    }
+}
+
+PUBLIC void st_print_dsentries_diff(st_init_info_t *info, int raw_diff, int print_changed)
+{
+    struct _magic_dsentry *dsentry;
+    ST_CHECK_INIT();
+
+    dsentry = st_cached_magic_vars.first_dsentry;
+    while (dsentry != NULL) {
+        struct _magic_sentry *cached_sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+        st_print_sentry_diff(info, cached_sentry, NULL, raw_diff, print_changed);
+        dsentry = dsentry->next;
+    }
+
+    dsentry = st_local_magic_vars_ptr->first_dsentry;
+    print_changed = FALSE;
+    while (dsentry != NULL) {
+        struct _magic_sentry *local_sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+        st_print_sentry_diff(info, NULL, local_sentry, raw_diff, print_changed);
+        dsentry = dsentry->next;
+    }
+}
+
+PUBLIC void st_print_functions_diff(st_init_info_t *info, int raw_diff, int print_changed)
+{
+    int i;
+    ST_CHECK_INIT();
+
+    for(i = 0 ; i < st_cached_magic_vars.functions_num ; i++) {
+        struct _magic_function *cached_function = &st_cached_magic_vars.functions[i];
+        st_print_function_diff(info, cached_function, NULL, raw_diff, print_changed);
+    }
+
+    print_changed = FALSE;
+    for (i = 0 ; i < st_local_magic_vars_ptr->functions_num ; i++) {
+        struct _magic_function *local_function = &st_local_magic_vars_ptr->functions[i];
+        st_print_function_diff(info, NULL, local_function, raw_diff, print_changed);
+    }
+}
+
+PUBLIC void st_print_state_diff(st_init_info_t *info, int raw_diff, int print_changed)
+{
+    ST_CHECK_INIT();
+
+    printf("Index: sentries\n");
+    printf("===================================================================\n");
+    st_print_sentries_diff(info, raw_diff, print_changed);
+
+    printf("\nIndex: dsentries\n");
+    printf("===================================================================\n");
+    st_print_dsentries_diff(info, raw_diff, print_changed);
+
+    printf("\nIndex: functions\n");
+    printf("===================================================================\n");
+    st_print_functions_diff(info, raw_diff, print_changed);
+    printf("\n");
+}
+
+PUBLIC int st_data_transfer(st_init_info_t *info)
+{
+    struct _magic_dsentry *dsentry;
+    int i, r;
+    int sentry_transferred;
+#if ST_DEBUG_DATA_TRANSFER
+    int counter = 1;
+#endif
+    ST_CHECK_INIT();
+
+    /* Check unpaired sentries. */
+    for (i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) {
+        struct _magic_sentry *sentry = &st_cached_magic_vars.sentries[i];
+        int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries);
+        if (!is_paired_sentry) {
+            r = check_unpaired_sentry(info, sentry);
+            if (r != OK) {
+                return r;
+            }
+        }
+    }
+
+    /* Check unpaired dsentries. */
+    dsentry = st_cached_magic_vars.first_dsentry;
+    while (dsentry != NULL) {
+        struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+        int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries);
+        if (!is_paired_sentry) {
+            r = check_unpaired_sentry(info, sentry);
+            if (r != OK) {
+                return r;
+            }
+        }
+        dsentry = dsentry->next;
+    }
+
+    /* Data transfer. */
+    do {
+        sentry_transferred = 0;
+
+#if ST_DEBUG_DATA_TRANSFER
+        printf("st_data_transfer: Round %d\n", counter++);
+        st_print_sentities(&st_cached_magic_vars);
+#endif
+
+        /* process sentries */
+#if ST_DEBUG_LEVEL > 0
+        printf("st_data_transfer: processing sentries\n");
+#endif
+        for(i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) {
+            struct _magic_sentry *sentry = &st_cached_magic_vars.sentries[i];
+            int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries);
+            int sentry_needs_transfer = MAGIC_STATE_EXTF_GET(sentry, ST_NEEDS_TRANSFER | ST_TRANSFER_DONE) == ST_NEEDS_TRANSFER;
+            if (sentry_needs_transfer && is_paired_sentry) {
+                r = transfer_data_sentry(info, sentry);
+                if (r != OK) {
+                    return r;
+                }
+                sentry_transferred = 1;
+            }
+        }
+
+        /* process dsentries */
+#if ST_DEBUG_LEVEL > 0
+        printf("st_data_transfer: processing dsentries\n");
+#endif
+        dsentry = st_cached_magic_vars.first_dsentry;
+        while (dsentry != NULL) {
+            struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+            int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries);
+            int sentry_needs_transfer = MAGIC_STATE_EXTF_GET(sentry, ST_NEEDS_TRANSFER | ST_TRANSFER_DONE) == ST_NEEDS_TRANSFER;
+            if (sentry_needs_transfer && is_paired_sentry) {
+                r = transfer_data_sentry(info, sentry);
+                if (r != OK) {
+                    return r;
+                }
+                sentry_transferred = 1;
+            }
+            dsentry = dsentry->next;
+        }
+
+    } while(sentry_transferred);
+
+    return OK;
+}
+
+PRIVATE INLINE void st_set_transfer_status(int status_flags, int status_op,
+    struct _magic_sentry *cached_sentry, struct _magic_function *cached_function)
+{
+#define __st_set_transfer_status(X)                         \
+    switch(status_op) {                                     \
+        case ST_OP_NONE:                                    \
+            return;                                         \
+        break;                                              \
+        case ST_OP_ADD:                                     \
+            MAGIC_STATE_EXTF_ADD(X, status_flags);          \
+        break;                                              \
+        case ST_OP_DEL:                                     \
+            MAGIC_STATE_EXTF_DEL(X, status_flags);          \
+        break;                                              \
+        case ST_OP_SET:                                     \
+            MAGIC_STATE_EXTF_SET(X, status_flags);          \
+        break;                                              \
+        case ST_OP_CLEAR:                                   \
+            MAGIC_STATE_EXTF_CLEAR(X);                      \
+        break;                                              \
+        default:                                            \
+            st_cbs_os.panic("Invalid operation!");          \
+        break;                                              \
+    }                                                       \
+
+    if (cached_sentry) {
+        __st_set_transfer_status(cached_sentry);
+    }
+    else {
+        assert(cached_function);
+        __st_set_transfer_status(cached_function);
+    }
+}
+
+PUBLIC void st_set_unpaired_types_ratios(float unpaired_types_ratio,
+    float unpaired_struct_types_ratio)
+{
+    st_unpaired_types_ratio = unpaired_types_ratio;
+    st_unpaired_struct_types_ratio = unpaired_struct_types_ratio;
+}
+
+PUBLIC void st_set_status_defaults(st_init_info_t *info)
+{
+    int match_all = ~0, skip_none = 0;
+    int skip_state_flags = (st_policies & ST_DEFAULT_SKIP_STACK) ? MAGIC_STATE_STACK : 0;
+
+    if (!(st_policies & ST_DEFAULT_TRANSFER_NONE)) {
+        /*
+         * Transfer all the (d)sentries by default. Skip stack dsentries when
+         * requested. In that case, stack dsentries won't be transferred and an
+         * error will be raised on stack pointer transfer.
+         */
+        st_set_status_by_state_flags(ST_NEEDS_TRANSFER, ST_OP_SET,
+            match_all, skip_state_flags);
+        if (st_policies & ST_DEFAULT_ALLOC_CASCADE_XFER) {
+            /*
+             * If requested, mark non-stack dsentries for cascade transfer
+             * instead of regular transfer.
+             */
+            st_set_status_by_state_flags(ST_ON_PTRXFER_CASCADE, ST_OP_SET,
+                MAGIC_STATE_HEAP | MAGIC_STATE_MAP, skip_none);
+        }
+    }
+    else {
+        /*
+         * Don't transfer any (d)sentries by default. Mark all the (d)sentries
+         * for cascade transfer (except for stack dsentries when requested).
+         */
+        st_set_status_by_state_flags(ST_ON_PTRXFER_CASCADE, ST_OP_SET,
+            match_all, skip_state_flags);
+    }
+
+    /*
+     * Always transfer all immutable objects.
+     */
+    st_set_status_by_state_flags(ST_NEEDS_TRANSFER, ST_OP_SET,
+        MAGIC_STATE_IMMUTABLE, skip_none);
+
+    /*
+     * If requested, mark library state dsentries as already transferred too.
+     */
+    if (st_policies & ST_DEFAULT_SKIP_LIB_STATE) {
+        st_set_status_by_state_flags(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE,
+            ST_OP_ADD, MAGIC_STATE_LIB, skip_none);
+    }
+
+    /*
+     * In addition, mark functions, out-of-band/string sentries
+     * and shared dsentries as already transferred.
+     */
+    st_set_status_by_state_flags(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE,
+        ST_OP_ADD, MAGIC_STATE_TEXT | MAGIC_STATE_OUT_OF_BAND |
+        MAGIC_STATE_STRING | MAGIC_STATE_CONSTANT | MAGIC_STATE_SHM, skip_none);
+
+    /*
+     * Finally, if we only want to transfer dirty sentries, mark all the other ones
+     * as already transferred.
+     */
+    if (st_policies & ST_TRANSFER_DIRTY_ONLY) {
+        st_set_status_by_state_flags(ST_TRANSFER_DONE, ST_OP_ADD, match_all, MAGIC_STATE_DIRTY_PAGE);
+    }
+
+#if DO_SKIP_ENVIRON_HACK
+    st_set_status_by_name(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE,
+        ST_OP_ADD, NULL, "__environ", MAGIC_DSENTRY_SITE_ID_NULL);
+    st_set_status_by_name(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE,
+        ST_OP_ADD, NULL, "stderr", MAGIC_DSENTRY_SITE_ID_NULL);
+#endif
+}
+
+PUBLIC void st_set_status_by_state_flags(int status_flags, int status_op,
+    int match_state_flags, int skip_state_flags)
+{
+    struct _magic_dsentry *dsentry = st_cached_magic_vars.first_dsentry;
+    int i;
+    int candidate_sentry_flags = MAGIC_STATE_DATA | MAGIC_STATE_STRING | MAGIC_STATE_CONSTANT | MAGIC_STATE_ADDR_NOT_TAKEN;
+    int candidate_function_flags = MAGIC_STATE_TEXT;
+    int candidate_dsentry_flags = ~(candidate_sentry_flags | candidate_function_flags);
+    ST_CHECK_INIT();
+
+    /* process sentries */
+    if (match_state_flags & candidate_sentry_flags) {
+        for (i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) {
+            int state_flags = st_cached_magic_vars.sentries[i].flags;
+            if ((state_flags & match_state_flags) && !(state_flags & skip_state_flags)) {
+                st_set_transfer_status(status_flags, status_op, &st_cached_magic_vars.sentries[i], NULL);
+            }
+        }
+    }
+
+    /* process dsentries */
+    if (match_state_flags & candidate_dsentry_flags) {
+        while (dsentry != NULL) {
+            int state_flags = dsentry->sentry.flags;
+            if ((state_flags & match_state_flags) && !(state_flags & skip_state_flags)) {
+                st_set_transfer_status(status_flags, status_op, MAGIC_DSENTRY_TO_SENTRY(dsentry), NULL);
+            }
+            dsentry = dsentry->next;
+        }
+    }
+
+    /* process functions */
+    if (match_state_flags & candidate_function_flags) {
+        for (i = 0 ; i < st_cached_magic_vars.functions_num ; i++) {
+            int state_flags = st_cached_magic_vars.functions[i].flags;
+            if ((state_flags & match_state_flags) && !(state_flags & skip_state_flags)) {
+                st_set_transfer_status(status_flags, status_op, NULL, &st_cached_magic_vars.functions[i]);
+            }
+        }
+    }
+}
+
+PUBLIC int st_set_status_by_function_ids(int status_flags, int status_op, _magic_id_t *ids)
+{
+    int r, i = 0;
+    while (ids[i] != 0) {
+        r = st_set_status_by_function_id(status_flags, status_op, ids[i]);
+        if (r != OK) {
+            return r;
+        }
+        i++;
+    }
+    return OK;
+}
+
+PUBLIC int st_set_status_by_sentry_ids(int status_flags, int status_op, _magic_id_t *ids)
+{
+    int r, i=0;
+    while (ids[i] != 0) {
+        r = st_set_status_by_sentry_id(status_flags, status_op, ids[i]);
+        if (r != OK) {
+            return r;
+        }
+        i++;
+    }
+    return OK;
+}
+
+PUBLIC int st_set_status_by_names(int status_flags, int status_op,
+    char **parent_names, char **names, _magic_id_t *dsentry_site_ids)
+{
+    int r, i = 0;
+    while (names[i] != NULL) {
+        r = st_set_status_by_name(status_flags, status_op,
+            parent_names ? parent_names[i] : NULL, names[i],
+            dsentry_site_ids ? dsentry_site_ids[i] :
+                MAGIC_DSENTRY_SITE_ID_NULL);
+        if (r != OK) {
+            return r;
+        }
+        i++;
+    }
+    return OK;
+}
+
+PUBLIC int st_set_status_by_local_addrs(int status_flags, int status_op,
+    void **addrs)
+{
+    int r, i=0;
+    while (addrs[i] != NULL) {
+        r = st_set_status_by_local_addr(status_flags, status_op, addrs[i]);
+        if (r != OK) {
+            return r;
+        }
+        i++;
+    }
+    return OK;
+}
+
+PUBLIC void st_set_status_by_sentry(int status_flags, int status_op,
+    void *cached_sentry)
+{
+    ST_CHECK_INIT();
+
+    st_set_transfer_status(status_flags, status_op,
+        (struct _magic_sentry*) cached_sentry, NULL);
+}
+
+PUBLIC void st_set_status_by_function(int status_flags, int status_op,
+    void *cached_function)
+{
+    ST_CHECK_INIT();
+
+    st_set_transfer_status(status_flags, status_op,
+        NULL, (struct _magic_function*) cached_function);
+}
+
+PUBLIC int st_set_status_by_name(int status_flags, int status_op,
+    char *parent_name, char *name, _magic_id_t dsentry_site_id)
+{
+    struct _magic_sentry *cached_sentry = NULL;
+    struct _magic_function *cached_function = NULL;
+    ST_CHECK_INIT();
+
+    EXEC_WITH_MAGIC_VARS(
+        cached_sentry = magic_sentry_lookup_by_name(parent_name ? parent_name : "", name, dsentry_site_id, NULL);
+        if (!cached_sentry) {
+            cached_function = magic_function_lookup_by_name(parent_name, name);
+        }
+        , &st_cached_magic_vars
+    );
+    if (!cached_sentry && !cached_function) {
+        return ENOENT;
+    }
+    st_set_transfer_status(status_flags, status_op, cached_sentry, cached_function);
+    if (cached_sentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) {
+        struct _magic_dsentry *prev_dsentry, *dsentry, *next_dsentry = MAGIC_DSENTRY_NEXT(MAGIC_DSENTRY_FROM_SENTRY(cached_sentry));
+        struct _magic_sentry* sentry;
+        /*
+         * Alloc sentries may have multiple instances with the same name.
+         * Use the site_id to distinguish between them.
+         */
+        assert(parent_name && name);
+        MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(next_dsentry, prev_dsentry, dsentry, sentry,
+            parent_name, name, dsentry_site_id,
+            st_set_transfer_status(status_flags, status_op, sentry, NULL);
+        );
+    }
+    return OK;
+}
+
+PUBLIC int st_set_status_by_function_id(int status_flags, int status_op,
+    _magic_id_t id)
+{
+    struct _magic_function *cached_function = NULL;
+    ST_CHECK_INIT();
+
+    EXEC_WITH_MAGIC_VARS(
+        cached_function = magic_function_lookup_by_id(id, NULL);
+        , &st_cached_magic_vars
+    );
+
+    if (!cached_function) {
+        return ENOENT;
+    }
+
+    st_set_transfer_status(status_flags, status_op, NULL, cached_function);
+    return OK;
+}
+
+PUBLIC int st_set_status_by_sentry_id(int status_flags, int status_op,
+    _magic_id_t id)
+{
+    struct _magic_sentry *cached_sentry = NULL;
+    ST_CHECK_INIT();
+
+    EXEC_WITH_MAGIC_VARS(
+        cached_sentry = magic_sentry_lookup_by_id(id, NULL);
+        , &st_cached_magic_vars
+    );
+
+    if (!cached_sentry) {
+        return ENOENT;
+    }
+
+    st_set_transfer_status(status_flags, status_op, cached_sentry, NULL);
+    return OK;
+}
+
+PUBLIC int st_set_status_by_local_addr(int status_flags, int status_op,
+    void *addr)
+{
+    char *parent_name, *name;
+    _magic_id_t dsentry_site_id = MAGIC_DSENTRY_SITE_ID_NULL;
+    struct _magic_sentry *sentry = NULL;
+    struct _magic_function *function = NULL;
+    ST_CHECK_INIT();
+
+    sentry = magic_sentry_lookup_by_addr(addr, NULL);
+    if (!sentry) {
+        function = magic_function_lookup_by_addr(addr, NULL);
+    }
+    if (sentry && !MAGIC_STATE_FLAG(sentry, MAGIC_STATE_DYNAMIC)) {
+        name = sentry->name;
+        parent_name = MAGIC_SENTRY_PARENT(sentry);
+        dsentry_site_id = MAGIC_SENTRY_SITE_ID(sentry);
+    }
+    else if (function && !MAGIC_STATE_FLAG(function, MAGIC_STATE_DYNAMIC)) {
+       name = function->name;
+       parent_name = MAGIC_FUNCTION_PARENT(function);
+    }
+    else {
+        return ENOENT;
+    }
+    st_set_status_by_name(status_flags, status_op, parent_name, name, dsentry_site_id);
+    return OK;
+}
+
+PUBLIC int st_pair_by_function_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op)
+{
+    int r, i=0;
+    ST_CHECK_INIT();
+
+    while (cached_ids[i] != 0) {
+        assert(local_ids[i] != 0);
+        r = st_pair_by_function_id(cached_ids[i], local_ids[i], status_flags, status_op);
+        if (r != OK) {
+            return r;
+        }
+        i++;
+    }
+    return OK;
+}
+
+PUBLIC int st_pair_by_sentry_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op)
+{
+    int r, i=0;
+    ST_CHECK_INIT();
+
+    while (cached_ids[i] != 0) {
+        assert(local_ids[i] != 0);
+        r = st_pair_by_sentry_id(cached_ids[i], local_ids[i], status_flags, status_op);
+        if (r != OK) {
+            return r;
+        }
+        i++;
+    }
+    return OK;
+}
+
+PUBLIC int st_pair_by_names(char **cached_parent_names, char **cached_names,
+    char **local_parent_names, char **local_names, _magic_id_t *dsentry_site_ids,
+    int status_flags, int status_op)
+{
+    int r, i=0;
+    while (cached_names[i] != NULL) {
+        assert(local_names[i]);
+        r = st_pair_by_name(cached_parent_names ? cached_parent_names[i] : NULL, cached_names[i],
+            local_parent_names ? local_parent_names[i] : NULL, local_names[i],
+            dsentry_site_ids ? dsentry_site_ids[i] : MAGIC_DSENTRY_SITE_ID_NULL,
+            status_flags, status_op);
+        if (r != OK) {
+            return r;
+        }
+        i++;
+    }
+    return OK;
+}
+
+PUBLIC void st_pair_by_sentry(void *cached_sentry, void *local_sentry, int status_flags, int status_op)
+{
+    ST_CHECK_INIT();
+
+    st_add_sentry_pair(cached_sentry, local_sentry);
+    if (cached_sentry) {
+        st_set_status_by_sentry(status_flags, status_op, cached_sentry);
+    }
+}
+
+PUBLIC void st_pair_by_function(void *cached_function, void* local_function, int status_flags, int status_op)
+{
+    ST_CHECK_INIT();
+
+    st_add_function_pair(cached_function, local_function);
+    if (cached_function) {
+        st_set_status_by_function(status_flags, status_op, cached_function);
+    }
+}
+
+PUBLIC int st_pair_alloc_by_dsindex(st_init_info_t *info, void *cached_sentry, void *local_dsindex, int num_elements, const union __alloc_flags *p_alloc_flags, int status_flags, int status_op)
+{
+    int r;
+    ST_CHECK_INIT();
+
+    r = st_add_sentry_pair_alloc_by_dsindex(info, cached_sentry, local_dsindex, num_elements, p_alloc_flags);
+    if (r != OK) {
+        return r;
+    }
+    if (cached_sentry) {
+        st_set_status_by_sentry(status_flags, status_op, cached_sentry);
+    }
+    return OK;
+}
+
+PUBLIC int st_pair_by_function_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op)
+{
+    struct _magic_function *cached_function = NULL, *local_function = NULL;
+    ST_CHECK_INIT();
+    assert(cached_id || local_id);
+
+    if (cached_id) {
+        EXEC_WITH_MAGIC_VARS(
+            cached_function = magic_function_lookup_by_id(cached_id, NULL);
+            , &st_cached_magic_vars
+        );
+        if (!cached_function) {
+            return ENOENT;
+        }
+    }
+    if (local_id) {
+        EXEC_WITH_MAGIC_VARS(
+            local_function = magic_function_lookup_by_id(local_id, NULL);
+            , st_local_magic_vars_ptr
+        );
+        if (!local_function) {
+            return ENOENT;
+        }
+    }
+
+    st_pair_by_function(cached_function, local_function, status_flags, status_op);
+    return OK;
+}
+
+PUBLIC int st_pair_by_sentry_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op)
+{
+    struct _magic_sentry *cached_sentry = NULL, *local_sentry = NULL;
+    ST_CHECK_INIT();
+    assert(cached_id || local_id);
+
+    if (cached_id) {
+        EXEC_WITH_MAGIC_VARS(
+            cached_sentry = magic_sentry_lookup_by_id(cached_id, NULL);
+            , &st_cached_magic_vars
+        );
+        if (!cached_sentry) {
+            return ENOENT;
+        }
+    }
+    if (local_id) {
+        EXEC_WITH_MAGIC_VARS(
+            local_sentry = magic_sentry_lookup_by_id(local_id, NULL);
+            , st_local_magic_vars_ptr
+        );
+        if (!local_sentry) {
+            return ENOENT;
+        }
+    }
+
+    st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op);
+    return OK;
+}
+
+PUBLIC int st_pair_by_name(char *cached_parent_name, char *cached_name,
+    char *local_parent_name, char *local_name, _magic_id_t dsentry_site_id,
+    int status_flags, int status_op)
+{
+    struct _magic_function *cached_function = NULL, *local_function = NULL;
+    struct _magic_sentry *cached_sentry = NULL, *local_sentry = NULL;
+    ST_CHECK_INIT();
+    assert(cached_name || local_name);
+
+    if (cached_name) {
+        EXEC_WITH_MAGIC_VARS(
+            cached_sentry = magic_sentry_lookup_by_name(cached_parent_name ? cached_parent_name : "", cached_name, dsentry_site_id, NULL);
+            if (cached_sentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) {
+                return EINVAL;
+            }
+            if (!cached_sentry) {
+                cached_function = magic_function_lookup_by_name(NULL, cached_name);
+            }
+            , &st_cached_magic_vars
+        );
+        if (!cached_sentry && !cached_function) {
+            return ENOENT;
+        }
+    }
+    if (local_name) {
+        EXEC_WITH_MAGIC_VARS(
+            if (!cached_function) {
+                local_sentry = magic_sentry_lookup_by_name(local_parent_name ? local_parent_name : "", local_name, dsentry_site_id, NULL);
+                if (local_sentry && MAGIC_SENTRY_IS_ALLOC(local_sentry)) {
+                    return EINVAL;
+                }
+            }
+            if (!cached_sentry && !local_sentry) {
+                local_function = magic_function_lookup_by_name(NULL, local_name);
+            }
+            , st_local_magic_vars_ptr
+        );
+        if (!local_sentry && !local_function) {
+            return ENOENT;
+        }
+    }
+    if (cached_function || local_function) {
+        assert(!cached_sentry && !local_sentry);
+        st_pair_by_function(cached_function, local_function, status_flags, status_op);
+        return OK;
+    }
+    assert(cached_sentry || local_sentry);
+    st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op);
+    return OK;
+}
+
+PUBLIC int st_pair_by_alloc_name_policies(st_init_info_t *info, char *cached_parent_name, char *cached_name, _magic_id_t cached_dsentry_site_id, char *local_parent_name, char *local_name, _magic_id_t local_dsentry_site_id, int num_elements, const union __alloc_flags *p_alloc_flags, int alloc_policies, int status_flags, int status_op)
+{
+    int r, saved_policies = st_policies;
+    st_policies &= ~(ST_ON_ALLOC_UNPAIR_MASK);
+    st_policies |= (alloc_policies & ST_ON_ALLOC_UNPAIR_MASK);
+    r = st_pair_by_alloc_name(info, cached_parent_name, cached_name, cached_dsentry_site_id, local_parent_name, local_name, local_dsentry_site_id, num_elements, p_alloc_flags, status_flags, status_op);
+    st_policies = saved_policies;
+    return r;
+}
+
+PUBLIC int st_pair_by_alloc_name(st_init_info_t *info, char *cached_parent_name, char *cached_name, _magic_id_t cached_dsentry_site_id, char *local_parent_name, char *local_name, _magic_id_t local_dsentry_site_id, int num_elements, const union __alloc_flags *p_alloc_flags, int status_flags, int status_op)
+{
+    struct _magic_sentry *cached_sentry = NULL, *local_sentry = NULL;
+    struct _magic_dsindex *local_dsindex = NULL;
+    struct _magic_dsentry *prev_dsentry, *dsentry, *head_dsentry;
+    struct _magic_sentry* sentry;
+    int r;
+    int is_cached_alloc = FALSE, is_local_alloc = FALSE;
+    ST_CHECK_INIT();
+    assert(cached_name || local_name);
+    assert(!((cached_name == NULL) ^ (cached_parent_name == NULL)));
+    assert(!((local_name == NULL) ^ (local_parent_name == NULL)));
+
+    if (cached_name) {
+        EXEC_WITH_MAGIC_VARS(
+            cached_sentry = magic_sentry_lookup_by_name(cached_parent_name,
+                cached_name, cached_dsentry_site_id, NULL);
+            if (cached_sentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) {
+                is_cached_alloc = TRUE;
+            }
+            , &st_cached_magic_vars
+        );
+    }
+    if (local_name) {
+        EXEC_WITH_MAGIC_VARS(
+            local_sentry = magic_sentry_lookup_by_name(local_parent_name,
+                local_name, local_dsentry_site_id, NULL);
+            if (local_sentry && MAGIC_SENTRY_IS_ALLOC(local_sentry)) {
+                is_local_alloc = TRUE;
+            }
+            if (!local_sentry || is_local_alloc) {
+                local_dsindex = magic_dsindex_lookup_by_name(local_parent_name, local_name);
+                if (local_dsindex && !MAGIC_DSINDEX_IS_ALLOC(local_dsindex)) {
+                    local_dsindex = NULL;
+                }
+                if (local_sentry) assert(local_dsindex);
+                is_local_alloc = is_local_alloc || local_dsindex != NULL;
+            }
+            , st_local_magic_vars_ptr
+        );
+    }
+    if (!is_cached_alloc && !is_local_alloc) {
+        if (cached_sentry || local_sentry) {
+            st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op);
+            return OK;
+        }
+        return ENOENT;
+    }
+    if (local_sentry) {
+        if (!is_local_alloc) {
+            /* Alloc sentries may have multiple instances with the same name. */
+            assert(cached_sentry && is_cached_alloc);
+            head_dsentry = MAGIC_DSENTRY_NEXT(MAGIC_DSENTRY_FROM_SENTRY(cached_sentry));
+            assert(cached_parent_name && cached_name);
+            MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(head_dsentry, prev_dsentry, dsentry, sentry, cached_parent_name, cached_name, cached_dsentry_site_id,
+                /* Cannot map multiple cached alloc sentries to a single local non-alloc sentry. */
+                return E2BIG;
+            );
+            /* Map a single cached alloc sentry to a single local non-alloc sentry. */
+            st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op);
+            return OK;
+        }
+        else {
+            /* Unpair all the local alloc sentries. */
+            head_dsentry = MAGIC_DSENTRY_FROM_SENTRY(local_sentry);
+            assert(local_parent_name && local_name);
+            MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(head_dsentry, prev_dsentry, dsentry, sentry, local_parent_name, local_name, local_dsentry_site_id,
+                st_pair_by_sentry(NULL, sentry, status_flags, status_op);
+            );
+        }
+    }
+    if (!cached_sentry) {
+        return OK;
+    }
+
+    /* Map a single cached non-alloc sentry to a local to-be-alloc sentry. */
+    if (!is_cached_alloc) {
+        assert(local_dsindex);
+        return st_pair_alloc_by_dsindex(info, cached_sentry, local_dsindex, num_elements, p_alloc_flags, status_flags, status_op);
+    }
+
+    /* Map all the cached alloc sentries to the corresponding local to-be-alloc sentries (or NULL). */
+    head_dsentry = MAGIC_DSENTRY_FROM_SENTRY(cached_sentry);
+    assert(cached_parent_name && cached_name);
+    MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(head_dsentry, prev_dsentry, dsentry,
+        sentry, cached_parent_name, cached_name, cached_dsentry_site_id,
+        r = st_pair_alloc_by_dsindex(info, sentry, local_dsindex, num_elements, p_alloc_flags, status_flags, status_op);
+        if (r != OK) {
+            return r;
+        }
+    );
+
+    return OK;
+}
+
+/* Metadata transfer and adjustment functions */
+
+PRIVATE int transfer_metadata_functions(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars,
+    struct _magic_vars_t *remote_magic_vars,
+    st_counterparts_t *counterparts)
+{
+
+    int i;
+    struct _magic_function *cached_function;
+
+    /* transfer magic_functions */
+    MD_TRANSFER(info, remote_magic_vars->functions, (void **)&cached_magic_vars->functions, remote_magic_vars->functions_num * sizeof(struct _magic_function));
+
+    /* adjust magic_functions */
+    for (i = 0 ; i < cached_magic_vars->functions_num ; i++) {
+        cached_function = &cached_magic_vars->functions[i];
+        MD_TRANSFER_STR(info, &cached_function->name);
+        cached_function->type = &cached_magic_vars->types[cached_function->type - remote_magic_vars->types];
+    }
+
+    return OK;
+}
+
+PRIVATE int transfer_metadata_dfunctions(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars,
+    struct _magic_vars_t *remote_magic_vars,
+    st_counterparts_t *counterparts)
+{
+
+    struct _magic_dfunction **dfunction_ptr;
+    struct _magic_dfunction *cached_dfunction, *prev_dfunction = NULL;
+    struct _magic_function *cached_function;
+
+    /* Transfer dfunctions. */
+    cached_magic_vars->first_dfunction = remote_magic_vars->first_dfunction;
+    dfunction_ptr = &cached_magic_vars->first_dfunction;
+    while (*dfunction_ptr != NULL) {
+        MD_TRANSFER(info, *dfunction_ptr, (void **)dfunction_ptr, sizeof(struct _magic_dfunction));
+        cached_dfunction = *dfunction_ptr;
+
+        /* Adjust dfunction parent_name and next/prev links. */
+        if (cached_dfunction->parent_name != NULL) {
+            MD_TRANSFER_STR(info, &cached_dfunction->parent_name);
+            if (strlen(cached_dfunction->parent_name) == 0) {
+                printf("ERROR. strlen(dfunction->parent_name) == 0.\n");
+                return EGENERIC;
+            }
+        } else {
+            printf("ERROR. dfunction->parent_name == NULL.\n");
+            return EGENERIC;
+        }
+
+        /* Adjust function name and type. */
+        cached_function = &cached_dfunction->function;
+        MD_TRANSFER_STR(info, &cached_function->name);
+        cached_function->type = &cached_magic_vars->types[cached_function->type - remote_magic_vars->types];
+
+        if (cached_dfunction->prev != NULL)
+            cached_dfunction->prev = prev_dfunction;
+
+        dfunction_ptr = &cached_dfunction->next;
+        prev_dfunction = cached_dfunction;
+    }
+
+    cached_magic_vars->last_dfunction = prev_dfunction;
+
+    return OK;
+}
+
+
+PUBLIC int st_transfer_metadata_types(st_init_info_t *info, struct _magic_vars_t *cached_magic_vars
+    , struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts)
+{
+
+    int i;
+
+    /* transfer types */
+    MD_TRANSFER(info, remote_magic_vars->types, (void **)&cached_magic_vars->types, remote_magic_vars->types_num * sizeof(struct _magic_type));
+
+    /* type adjustments */
+    for (i = 0 ; i < cached_magic_vars->types_num ; i++) {
+        if (transfer_metadata_type_members(info, &cached_magic_vars->types[i], cached_magic_vars, remote_magic_vars)) {
+            printf("ERROR transferring type members metadata.\n");
+            return EGENERIC;
+        }
+        set_typename_key(&cached_magic_vars->types[i]);
+    }
+
+    return OK;
+}
+
+PRIVATE int transfer_metadata_type_value_set(st_init_info_t *info, struct _magic_type *type, struct _magic_vars_t *cached_magic_vars, struct _magic_vars_t *remote_magic_vars)
+{
+    int num_elements;
+    /* MD_TRANSFER cannot be used, because it will allocate space for num_elements */
+    if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) type->value_set, sizeof(int), (uint32_t) &num_elements)) {
+        printf("ERROR transferring type value set metadata.\n");
+        return EGENERIC;
+    }
+    num_elements++;
+    MD_TRANSFER(info, type->value_set, (void **)&type->value_set, num_elements *sizeof(int));
+    return OK;
+}
+
+PRIVATE int transfer_metadata_type_members(st_init_info_t *info, struct _magic_type *type, struct _magic_vars_t *cached_magic_vars, struct _magic_vars_t *remote_magic_vars)
+{
+    int r;
+    int num_child = MAGIC_TYPE_NUM_CONTAINED_TYPES(type), i;
+
+    MD_TRANSFER_STR(info, &type->name);
+    MD_TRANSFER_STR(info, &type->type_str);
+
+    if (type->names != NULL && type->num_names > 0) {
+        /* transfer array of name pointers */
+        MD_TRANSFER(info, type->names, (void **)&type->names, type->num_names * sizeof(char *));
+        for (i = 0 ; i < type->num_names ; i++) {
+            /* transfer individual name */
+            MD_TRANSFER_STR(info, &type->names[i]);
+        }
+    }
+
+
+#define MD_TRANSFER_ADJUST_MEMBER_PTR(NUM_ELEMENTS,                            \
+    ELEMENT_SIZE,PTR_ARRAY,INDEX)                                              \
+    if((NUM_ELEMENTS) > 0 && (PTR_ARRAY) != NULL) {                            \
+        MD_TRANSFER(info, PTR_ARRAY, (void **)&PTR_ARRAY,                      \
+            NUM_ELEMENTS * ELEMENT_SIZE);                                      \
+        for(INDEX = 0 ; (INDEX) < (NUM_ELEMENTS) ; INDEX++) {                  \
+            PTR_ARRAY[INDEX] = ADJUST_POINTER(cached_magic_vars->types,        \
+                remote_magic_vars->types, PTR_ARRAY[INDEX]);                   \
+        }                                                                      \
+    }
+
+    MD_TRANSFER_ADJUST_MEMBER_PTR(
+        (type->type_id == MAGIC_TYPE_FUNCTION ? num_child + 1 : num_child),
+        sizeof(struct _magic_type *), type->contained_types, i
+    );
+
+    if (type->compatible_types) {
+        struct _magic_type *comp_types_element;
+        int comp_types_size=0;
+        /* determine size of array */
+        do {
+            if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) &type->compatible_types[comp_types_size]
+                , sizeof(struct _magic_type *), (uint32_t) &comp_types_element))
+            {
+                printf("ERROR transferring compatible types array metadata.\n");
+                return EGENERIC;
+            }
+            comp_types_size++;
+        } while(comp_types_element != NULL);
+        /* We know the size, now transfer the whole array */
+        MD_TRANSFER(info, type->compatible_types, (void **) &type->compatible_types, comp_types_size * sizeof(struct _magic_type *));
+        for (i = 0; i < comp_types_size; i++) {
+            if (type->compatible_types[i] != NULL) {
+                /* Adjust the pointer to point to the local counterpart */
+                type->compatible_types[i] = ADJUST_POINTER(cached_magic_vars->types,  remote_magic_vars->types, type->compatible_types[i]);
+            }
+        }
+    }
+
+    if (num_child>0 && type->member_names != NULL) {
+        MD_TRANSFER(info, type->member_names, (void **)&type->member_names, num_child * sizeof(char *));
+        for (i = 0 ; i < num_child ; i++) {
+            MD_TRANSFER_STR(info, &type->member_names[i]);
+        }
+    }
+
+    if (num_child>0 && type->member_offsets != NULL) {
+        MD_TRANSFER(info, type->member_offsets, (void **)&type->member_offsets, num_child * sizeof(unsigned));
+    }
+
+    if (MAGIC_TYPE_HAS_VALUE_SET(type)) {
+        r = transfer_metadata_type_value_set(info, type, cached_magic_vars, remote_magic_vars);
+        if (r != OK) {
+            return r;
+        }
+    }
+    return OK;
+}
+
+PRIVATE int transfer_metadata_sentries(st_init_info_t *info, struct _magic_vars_t *cached_magic_vars
+    , struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts
+    , int *max_buff_sz)
+{
+
+    int i;
+    int skipped_sentries = 0;
+    struct _magic_sentry *cached_sentry;
+
+    /* transfer sentries */
+    MD_TRANSFER(info, remote_magic_vars->sentries, (void **)&cached_magic_vars->sentries, remote_magic_vars->sentries_num * sizeof(struct _magic_sentry));
+    /* todo: try to use only remote_magic_vars or cached magic_vars */
+    /* todo: if transfer is complete, and argument 2 and 3 are always the same, remove 2nd argument */
+
+    /* adjust sentries */
+    for (i = 0 ; i < cached_magic_vars->sentries_num ; i++) {
+        cached_sentry = &cached_magic_vars->sentries[i];
+
+        if ((st_policies & ST_TRANSFER_DIRTY_ONLY) &&
+            !MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DIRTY_PAGE) &&
+            !MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_IMMUTABLE)) {
+            skipped_sentries++;
+            continue;
+        }
+        if (skipped_sentries > 0) {
+            cached_magic_vars->sentries[i - skipped_sentries] =
+                cached_magic_vars->sentries[i];
+            cached_magic_vars->sentries[i - skipped_sentries].id -=
+                skipped_sentries;
+            cached_sentry = &cached_magic_vars->sentries[i - skipped_sentries];
+        }
+
+
+        if (transfer_metadata_sentry_members(info, cached_sentry)) {
+            printf("ERROR transferring sentry members metadata.\n");
+            return EGENERIC;
+        }
+
+        /*
+         * We have to change the type to its cached counterpart,
+         * so that it may be compared to the local type of the local sentry counterpart.
+         */
+        cached_sentry->type = &cached_magic_vars->types[cached_sentry->type - remote_magic_vars->types];
+
+        if (cached_sentry->type->size > *max_buff_sz) {
+            *max_buff_sz = cached_sentry->type->size;
+        }
+    }
+
+    if (skipped_sentries > 0)
+        cached_magic_vars->sentries_num -= skipped_sentries;
+
+    return OK;
+}
+
+PRIVATE int transfer_metadata_sentry_members(st_init_info_t *info, struct _magic_sentry *sentry)
+{
+    if (sentry->name != NULL) {
+        MD_TRANSFER_STR(info, &sentry->name);
+    } else {
+        printf("ERROR. sentry->name == NULL.\n");
+        return EGENERIC;
+    }
+    return OK;
+}
+
+PUBLIC int st_transfer_metadata_dsentries(st_init_info_t *info, struct _magic_vars_t *cached_magic_vars
+    , struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts, int *max_buff_sz, int *dsentries_num)
+{
+
+    struct _magic_dsentry **dsentry_ptr;
+#if MAGIC_DSENTRY_ALLOW_PREV
+    struct _magic_dsentry *prev_dsentry = NULL;
+#endif
+    int r;
+
+    *dsentries_num = 0;
+
+    cached_magic_vars->first_dsentry = remote_magic_vars->first_dsentry;
+    dsentry_ptr = &cached_magic_vars->first_dsentry;
+    while (*dsentry_ptr != NULL) {
+
+        struct _magic_dsentry *cached_dsentry, *remote_dsentry = *dsentry_ptr;
+        struct _magic_sentry *sentry;
+
+        /* transfer dsentry */
+        MD_TRANSFER(info, *dsentry_ptr, (void **) dsentry_ptr, sizeof(struct _magic_dsentry));
+        cached_dsentry = *dsentry_ptr;
+
+        if ((st_policies & ST_TRANSFER_DIRTY_ONLY) &&
+            !MAGIC_STATE_FLAG((&cached_dsentry->sentry), MAGIC_STATE_DIRTY_PAGE) &&
+            !MAGIC_STATE_FLAG((&cached_dsentry->sentry), MAGIC_STATE_IMMUTABLE)) {
+            *dsentry_ptr = cached_dsentry->next;
+            continue;
+        }
+
+        if (cached_magic_vars->first_stack_dsentry == remote_dsentry) {
+            cached_magic_vars->first_stack_dsentry = cached_dsentry;
+        } else if(cached_magic_vars->last_stack_dsentry == remote_dsentry) {
+            cached_magic_vars->last_stack_dsentry = cached_dsentry;
+        }
+
+        /* adjust dsentry */
+        if (cached_dsentry->parent_name != NULL) {
+            MD_TRANSFER_STR(info, &cached_dsentry->parent_name);
+            if (strlen(cached_dsentry->parent_name) == 0) {
+                printf("ERROR. strlen(dsentry->parent_name) == 0.\n");
+#if TODO_DSENTRY_PARENT_NAME_BUG
+                if (cached_dsentry->next != NULL)
+#endif
+                    return EGENERIC;
+            }
+        } else {
+            printf("ERROR. dsentry->parent_name == NULL.\n");
+            return EGENERIC;
+        }
+
+        sentry = &cached_dsentry->sentry;
+        if (transfer_metadata_sentry_members(info, sentry)) {
+            printf("ERROR transferring sentry members metadata.\n");
+            return EGENERIC;
+        }
+
+        /* Override original id to simplify pairing later. */
+        sentry->id = cached_magic_vars->sentries_num + *dsentries_num + 1;
+
+        /*
+         * Report violations for all the pointers pointing to the initial stack area.
+         * This is to make sure no assumption is incorrectly made about this area.
+         */
+        if (!strcmp(sentry->name, MAGIC_ALLOC_INITIAL_STACK_NAME)) {
+            sentry->flags |= MAGIC_STATE_ADDR_NOT_TAKEN;
+        }
+
+        /*
+         * Adjust the type, so that the local and remote type can be compared
+         * during a server version update
+         */
+        if (sentry->type == &remote_dsentry->type) {
+
+            /*
+             * sentry->type is contained in dsentry.type. Therefore, this is an
+             * array type. In order to allocate a new memory region, we only
+             * need the size of the type, and the contained type as arguments
+             * to the magic allocation function. Therefore, other members of
+             * the type do need to be cached or adjusted.
+             */
+
+            /* Adjust pointer to cached location */
+            sentry->type = &cached_dsentry->type;
+
+            /* Adjust contained_types to type_array located in dsentry struct. */
+            sentry->type->contained_types = cached_dsentry->type_array;
+
+            /*
+             * Adjust only pointer in type_array. It currently has the same
+             * value as the remote copy, but it has to point to the cached
+             * of the contained type.
+             */
+            sentry->type->contained_types[0] = &cached_magic_vars->types[sentry->type->contained_types[0] - remote_magic_vars->types];
+
+            /* Adjust empty strings. */
+            sentry->type->name = "";
+            sentry->type->type_str = "";
+
+            /* Adjust value set if necessary. */
+            if (MAGIC_TYPE_HAS_VALUE_SET(sentry->type)) {
+                r = transfer_metadata_type_value_set(info, sentry->type, cached_magic_vars, remote_magic_vars);
+                if (r != OK) {
+                    return r;
+                }
+            }
+        } else {
+
+            /*
+             * sentry.type must be in the global type array. Adjust pointer accordingly.
+             * The pointer is still pointing to the remote version.
+             * We have to change it to the cached version.
+             */
+            sentry->type = &cached_magic_vars->types[sentry->type - remote_magic_vars->types];
+
+        }
+
+        /* see if the buffer needs to be bigger for the dsentry data region. */
+        if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND) && *max_buff_sz < sentry->type->size) {
+            *max_buff_sz = sentry->type->size;
+        }
+
+        dsentry_ptr = &cached_dsentry->next;
+#if MAGIC_DSENTRY_ALLOW_PREV
+        if (cached_dsentry->prev != NULL)
+            cached_dsentry->prev = prev_dsentry;
+        prev_dsentry = cached_dsentry;
+#endif
+        *dsentries_num = *dsentries_num + 1;
+    }
+
+    return OK;
+}
+
+PRIVATE int pair_metadata_types(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts, int allow_unpaired_types)
+{
+    int i, j, num_unpaired_struct_types = 0;
+    int num_unpaired_types = 0;
+    int num_total_types = 0;
+    int num_struct_types = 0;
+    int num_unpaired_types_left, num_unpaired_struct_types_left;
+
+    if (st_unpaired_types_ratio > 0 || st_unpaired_struct_types_ratio > 0) {
+        for (i = 0 ; i < cached_magic_vars->types_num ; i++) {
+            struct _magic_type *type = &cached_magic_vars->types[i];
+            if (ST_IS_UNPAIRABLE_STRUCT_TYPE(type)) {
+                num_struct_types++;
+            }
+            if (ST_IS_UNPAIRABLE_TYPE(type)) {
+                num_total_types++;
+            }
+        }
+        num_unpaired_types = (int) (st_unpaired_types_ratio*num_total_types);
+        num_unpaired_struct_types = (int) (st_unpaired_struct_types_ratio*num_struct_types);
+    }
+    num_unpaired_types_left = num_unpaired_types;
+    num_unpaired_struct_types_left = num_unpaired_struct_types;
+
+    /* type pairing, remote->local */
+    for(i = 0 ; i < cached_magic_vars->types_num ; i++) {
+        struct _magic_type *type = &cached_magic_vars->types[i];
+        counterparts->types[i].counterpart = NULL;
+
+        if (num_unpaired_types_left > 0 && ST_IS_UNPAIRABLE_TYPE(type)) {
+            num_unpaired_types_left--;
+            continue;
+        }
+        else if (num_unpaired_struct_types_left > 0 && ST_IS_UNPAIRABLE_STRUCT_TYPE(type)) {
+            num_unpaired_struct_types_left--;
+            continue;
+        }
+
+        for (j = 0 ; j < _magic_types_num ; j++) {
+            /* A remote type may be paired to multiple local types.
+             * It is safe to index only the first type since counterparts
+             * are only used to speed up type matching.
+             */
+            if (magic_type_compatible(type, &_magic_types[j], MAGIC_TYPE_COMPARE_ALL)) {
+                counterparts->types[i].counterpart = &_magic_types[j];
+                break;
+            }
+        }
+
+        if (!allow_unpaired_types && counterparts->types[i].counterpart == NULL) {
+             printf("ERROR, remote type cannot be paired with a local type: ");
+             MAGIC_TYPE_PRINT(type, MAGIC_EXPAND_TYPE_STR);
+             printf("\n");
+             return EGENERIC;
+        }
+    }
+    if (st_unpaired_types_ratio > 0 || st_unpaired_struct_types_ratio > 0) {
+        assert(num_unpaired_types_left == 0 && (st_unpaired_types_ratio > 0 || num_unpaired_struct_types == 0));
+        _magic_printf("Unpaired types stats: unpaired types: %d, total types: %d, unpaired struct types: %d, struct types: %d\n", num_unpaired_types, num_total_types, num_unpaired_struct_types, num_struct_types);
+    }
+
+    for (i = 0 ; i < cached_magic_vars->types_num ; i++) {
+        struct _magic_type *type = &cached_magic_vars->types[i];
+        struct _magic_type *local_type = (struct _magic_type*) counterparts->types[i].counterpart;
+        counterparts->ptr_types[i].counterpart = NULL;
+        if (local_type && type->type_id == MAGIC_TYPE_POINTER) {
+            if (MAGIC_TYPE_HAS_COMP_TYPES(type) != MAGIC_TYPE_HAS_COMP_TYPES(local_type)) {
+                continue;
+            }
+            if (MAGIC_TYPE_HAS_COMP_TYPES(type)) {
+                j = 0;
+                while (MAGIC_TYPE_HAS_COMP_TYPE(type, j) && MAGIC_TYPE_HAS_COMP_TYPE(local_type, j)) {
+                    struct _magic_type *ctype = MAGIC_TYPE_COMP_TYPE(type, j);
+                    struct _magic_type *local_ctype = MAGIC_TYPE_COMP_TYPE(local_type, j);
+                    if (!ST_TYPE_IS_CACHED_COUNTERPART(ctype, local_ctype)) {
+                        break;
+                    }
+                    j++;
+                }
+                if (MAGIC_TYPE_HAS_COMP_TYPE(type, j) || MAGIC_TYPE_HAS_COMP_TYPE(local_type, j)) {
+                    continue;
+                }
+            }
+            counterparts->ptr_types[i].counterpart = local_type;
+        }
+    }
+
+    return OK;
+}
+
+PRIVATE int pair_metadata_functions(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
+{
+    int i;
+    struct _magic_function *cached_function, *local_function;
+#if ST_DEBUG_LEVEL > 0
+    int num_relocated = 0;
+#endif
+
+    /* map remote functions to local functions */
+    for(i = 0 ; i < cached_magic_vars->functions_num ; i++) {
+        cached_function = &cached_magic_vars->functions[i];
+        local_function = NULL;
+        st_map_functions(&cached_function, &local_function);
+        ST_SET_CACHED_COUNTERPART(cached_function, functions, functions, local_function);
+
+#if CHECK_SENTITY_PAIRS
+        if (local_function) {
+            /* debug: see if the function is paired more than once */
+            struct _magic_function *cfunction = NULL;
+            st_map_functions(&cfunction, &local_function);
+            if (cfunction != cached_function) {
+                printf("function pairing failed for (1) local function linked to multiple remote functions (2), (3)\n");
+                printf("(1) "); MAGIC_FUNCTION_PRINT(local_function, 0); printf("\n");
+                printf("(2) "); MAGIC_FUNCTION_PRINT(cached_function, 0); printf("\n");
+                printf("(3) "); MAGIC_FUNCTION_PRINT(cfunction, 0); printf("\n");
+                return EGENERIC;
+            }
+        }
+#endif
+
+#if ST_DEBUG_LEVEL > 0
+        if (local_function && cached_function->address != local_function->address) {
+            num_relocated++;
+            if (ST_DEBUG_LEVEL > 1) {
+                printf("- relocated function: '%s'\n", cached_magic_vars->functions[i].name);
+            }
+        }
+#endif
+    }
+
+#if ST_DEBUG_LEVEL > 0
+    printf("total remote functions: %d. relocated: %d\n", cached_magic_vars->functions_num, num_relocated);
+#endif
+
+    return OK;
+}
+
+PRIVATE int pair_metadata_sentries(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
+{
+    int i, r;
+    struct _magic_sentry *cached_sentry, *local_sentry;
+#if ST_DEBUG_LEVEL > 0
+    int num_relocated_str = 0, num_relocated_normal = 0;
+#endif
+
+    /* pair sentries remote->local */
+    for (i = 0 ; i < cached_magic_vars->sentries_num ; i++) {
+        void *local_data_addr = NULL;
+        cached_sentry = &cached_magic_vars->sentries[i];
+
+        /* String data is transferred directly. */
+        if (MAGIC_SENTRY_IS_STRING(cached_sentry)) {
+            char *string = st_buff_allocate(info, cached_sentry->type->size);
+            if (!string) {
+                printf("ERROR allocating string.\n");
+                return EGENERIC;
+            }
+            r = st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) cached_sentry->address,
+                 cached_sentry->type->size, (uint32_t) string);
+            if(r != OK) {
+                printf("ERROR transferring string.\n");
+                return EGENERIC;
+            }
+            local_data_addr = string;
+        }
+        ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries_data, local_data_addr);
+
+        local_sentry = NULL;
+        st_map_sentries(&cached_sentry, &local_sentry);
+        ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry);
+
+#if CHECK_SENTITY_PAIRS
+        if (local_sentry && !MAGIC_SENTRY_IS_STRING(cached_sentry)) {
+            /* debug: see if the non-string sentry is paired more than once */
+            struct _magic_sentry *csentry = NULL;
+            st_map_sentries(&csentry, &local_sentry);
+            if (csentry != cached_sentry) {
+                printf("sentry pairing failed for (1) local sentry linked to multiple remote sentries (2), (3)\n");
+                printf("(1) "); MAGIC_SENTRY_PRINT(local_sentry, 0); printf("\n");
+                printf("(2) "); MAGIC_SENTRY_PRINT(cached_sentry, 0); printf("\n");
+                printf("(3) "); MAGIC_SENTRY_PRINT(csentry, 0); printf("\n");
+                return EGENERIC;
+            }
+        }
+#endif
+
+#if ST_DEBUG_LEVEL > 0
+        if (local_sentry && cached_sentry->address != local_sentry->address) {
+            if (MAGIC_SENTRY_IS_STRING(cached_sentry)) {
+                num_relocated_str++;
+            }
+            else {
+                num_relocated_normal++;
+                if (ST_DEBUG_LEVEL > 1) {
+                    printf("- relocated non-string sentry: '%s'\n", cached_sentry->name);
+                }
+            }
+        }
+#endif
+    }
+
+#if ST_DEBUG_LEVEL > 0
+    printf("total remote sentries: %d. relocated normal: %d relocated string: %d\n", cached_magic_vars->sentries_num, num_relocated_normal, num_relocated_str);
+#endif
+
+    return OK;
+}
+
+#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
+PRIVATE int allocate_pair_metadata_dsentries_from_raw_copy(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
+{
+    struct _magic_dsentry *dsentry;
+    int remote_dsentries = 0, unpaired_dsentries = 0;
+
+#if ST_DEBUG_LEVEL > 3
+    EXEC_WITH_MAGIC_VARS(
+        magic_print_dsentries();
+        , &st_cached_magic_vars
+    );
+    magic_print_dsentries();
+#endif
+
+    dsentry = cached_magic_vars->first_dsentry;
+    while (dsentry != NULL) {
+        struct _magic_sentry *local_sentry = NULL, *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+
+        /* Initialize counterpart to NULL. */
+        ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, NULL);
+
+        remote_dsentries++;
+
+        if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_STACK) && !MAGIC_STATE_FLAG(sentry, MAGIC_STATE_LIB)) {
+            local_sentry = MAGIC_DSENTRY_TO_SENTRY((struct _magic_dsentry *)MAGIC_PTR_FROM_DATA(sentry->address));
+        } else {
+#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
+            EXEC_WITH_MAGIC_VARS(
+                local_sentry = magic_sentry_lookup_by_range(sentry->address, NULL);
+                , &st_cached_magic_vars
+            );
+#else
+            local_sentry = magic_sentry_lookup_by_addr(sentry->address, NULL);
+#endif
+        }
+
+        if (!local_sentry) {
+             unpaired_dsentries++;
+#if ST_DEBUG_LEVEL > 2
+             printf("allocate_pair_metadata_dsentries_from_raw_copy: found unpaired "); MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR); _magic_printf("\n");
+#endif
+        }
+        ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry);
+        dsentry = dsentry->next;
+    }
+
+#if ST_DEBUG_LEVEL > 0
+    printf("total remote dsentries: %d (%d unpaired)\n", remote_dsentries, unpaired_dsentries);
+#endif
+
+    return OK;
+}
+
+#else
+
+PRIVATE int allocate_pair_metadata_dsentries(st_init_info_t *info,
+    struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
+{
+    struct _magic_dsentry *dsentry = cached_magic_vars->first_dsentry, *local_dsentry;
+    int remote_dsentries = 0;
+#ifndef __MINIX
+    int *local_sentry_paired_by_id = st_buff_allocate(info, (_magic_sentries_next_id + 1) * sizeof(int));
+#endif
+
+#if ST_DEBUG_LEVEL > 3
+    EXEC_WITH_MAGIC_VARS(
+        magic_print_dsentries();
+        , &st_cached_magic_vars
+    );
+    magic_print_dsentries();
+#endif
+
+#ifdef __MINIX
+    /*
+     * Since on MINIX the mmaped regions are inherited in the new process,
+     * we must first deallocate them. This is not the case on Linux.
+     */
+    while (dsentry != NULL) {
+        int res = 0;
+        struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+        int size = sentry->type->size;
+        /* For mmap first unmap the old region that is already mapped into this new instance */
+        if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)
+                && MAGIC_STATE_REGION(sentry) == MAGIC_STATE_MAP
+                && !USE_PRE_ALLOCATED_BUFFER(info)
+           )
+            {
+            /*
+             * The 'ext' field in the dsentry is used here to record
+             * the padding for ASR.
+             */
+            size_t padding = (size_t) dsentry->ext;
+            /*
+             * call munmap(). ptr and size have to be altered,
+             * in order to free the preceding page, containing the dsentry struct, too.
+             */
+            MAGIC_MEM_WRAPPER_BLOCK(
+                res = munmap((char *)sentry->address - magic_get_sys_pagesize() - padding, size + magic_get_sys_pagesize() + padding);
+            );
+            if (res != 0) {
+                printf("ERROR, munmap returned NULL.\n");
+                return EGENERIC;
+            }
+        }
+        dsentry = dsentry->next;
+    }
+#endif
+
+    /* Permute dsentries in case of ASR. */
+    if (info->flags & ST_LU_ASR) {
+        magic_asr_permute_dsentries(&cached_magic_vars->first_dsentry);
+    }
+
+    dsentry = cached_magic_vars->first_dsentry;
+    while (dsentry != NULL) {
+        struct _magic_sentry *local_sentry, *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+        int is_alloc_dsentry = MAGIC_SENTRY_IS_ALLOC(sentry);
+        int res = 0;
+        struct _magic_dsindex *local_dsindex;
+
+        remote_dsentries++;
+
+#ifdef __MINIX
+        /* Cannot deal with dead dsentries. */
+        assert(dsentry->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE);
+#else
+        /*
+         * If there are dead dsentries, we simply skip them.
+         */
+        if (dsentry->magic_state != MAGIC_DSENTRY_MSTATE_ALIVE) {
+            dsentry = dsentry->next;
+            continue;
+        }
+#endif
+
+        /* Initialize counterpart to NULL. */
+        ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, NULL);
+
+        /* Handle non-alloc dsentries first. */
+        if (!is_alloc_dsentry) {
+            local_sentry = magic_sentry_lookup_by_name(dsentry->parent_name,
+                sentry->name, dsentry->site_id, NULL);
+            if (local_sentry) {
+                assert(!MAGIC_SENTRY_IS_ALLOC(local_sentry));
+                ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry);
+            }
+
+            dsentry = dsentry->next;
+            continue;
+        }
+
+        /* Out-of-band alloc dsentries next. */
+        if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) {
+            struct _magic_type *type;
+            /* We can only handle obdsentries with the magic void type, transferred as-is. */
+            if (sentry->type != &dsentry->type) {
+                /* Not an array type */
+                type = sentry->type;
+            } else {
+                /* This is an array type, use its contained type instead. */
+                type = sentry->type->contained_types[0];
+            }
+            /* We now have the cached version of the type. Compare it to magic void type */
+            if (!magic_type_compatible(type, MAGIC_VOID_TYPE, MAGIC_TYPE_COMPARE_ALL)) {
+                printf("Can't handle obdsentry with non-void type\n");
+                return EGENERIC;
+            }
+#ifdef __MINIX
+            /* On MINIX we need to recreate all the obdsentries. */
+            struct _magic_obdsentry *obdsentry;
+            int size = sentry->type->size;
+            obdsentry = magic_create_obdsentry(sentry->address,
+                MAGIC_VOID_TYPE, size, MAGIC_STATE_REGION(sentry), sentry->name, dsentry->parent_name);
+            if (obdsentry == NULL) {
+                printf("ERROR, magic_create_obdsentry returned NULL.\n");
+                return EGENERIC;
+            }
+            local_dsentry = MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry);
+#else
+            /* On Linux we only need to pair them. */
+            local_sentry = magic_sentry_lookup_by_name(
+                MAGIC_SENTRY_PARENT(sentry), sentry->name,
+                MAGIC_SENTRY_SITE_ID(sentry), NULL);
+            if (local_sentry == NULL) {
+                printf("Unable to pair obdsentry.\n");
+                return EGENERIC;
+            }
+            local_dsentry = MAGIC_DSENTRY_FROM_SENTRY(local_sentry);
+#endif
+            ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, MAGIC_DSENTRY_TO_SENTRY(local_dsentry));
+            dsentry = dsentry->next;
+            continue;
+        }
+
+        /* Handle regular alloc dsentries last. */
+#ifndef __MINIX
+        /*
+         * For Linux, first pair INIT time remote
+         * dsentries with local dsentries.
+         */
+
+        if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_INIT)) {
+            local_sentry = NULL;
+
+            if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_IMMUTABLE)) {
+                /*
+                 * Immutable init time dsentries should have already been
+                 * preallocated, so just pair them by address.
+                 */
+                local_sentry = magic_sentry_lookup_by_addr(sentry->address, NULL);
+            } else {
+#if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH
+                struct _magic_sentry_list *local_sentry_list;
+                local_sentry_list = magic_sentry_list_lookup_by_name_hash(
+                    dsentry->parent_name, sentry->name, dsentry->site_id, NULL);
+
+                while (local_sentry_list) {
+                    if (!local_sentry_paired_by_id[local_sentry_list->sentry->id]) {
+                        local_sentry = local_sentry_list->sentry;
+                        break;
+                    }
+                    local_sentry_list = local_sentry_list->next;
+                }
+
+#else
+                do {
+                    struct _magic_dsentry *prev_dsentry, *tmp_dsentry;
+                    struct _magic_sentry *tmp_sentry;
+                    MAGIC_DSENTRY_LOCK();
+                    MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry,
+                        tmp_dsentry, tmp_sentry,
+                        if (!strcmp(tmp_sentry->name, sentry->name)) {
+                            if (!dsentry->parent_name ||
+                                    !strcmp(MAGIC_SENTRY_PARENT(tmp_sentry), dsentry->parent_name)) {
+                                if (dsentry->site_id == MAGIC_DSENTRY_SITE_ID_NULL ||
+                                        tmp_dsentry->site_id == dsentry->site_id) {
+                                    if (!local_sentry_paired_by_id[tmp_sentry->id]) {
+                                        local_sentry = tmp_sentry;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    );
+                    MAGIC_DSENTRY_UNLOCK();
+                } while (0);
+#endif
+            }
+            if (local_sentry) {
+                ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry);
+                local_sentry_paired_by_id[local_sentry->id] = 1;
+                dsentry = dsentry->next;
+                continue;
+            }
+        }
+#endif
+
+        /*
+         * Just recreate all the other dsentries. Immutable objects will
+         * have already been inherited and allocate_local_dsentry() will
+         * not reallocate them, but instead it will just create a new
+         * local dsentry in the right place.
+         */
+        local_dsindex = magic_dsindex_lookup_by_name(dsentry->parent_name, sentry->name);
+        if (local_dsindex || MAGIC_SENTRY_IS_LIB_ALLOC(sentry)) {
+
+            /* Allocate a new local dsentry and pair it with the remote. */
+            res = allocate_local_dsentry(info, local_dsindex, 0, 0, NULL, &local_dsentry, dsentry, NULL);
+            if (res != ENOSYS) {
+                if (res != OK) {
+                    return res;
+                }
+                assert(local_dsentry);
+                ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, MAGIC_DSENTRY_TO_SENTRY(local_dsentry));
+            }
+        }
+        dsentry = dsentry->next;
+    }
+
+#if ST_DEBUG_LEVEL > 0
+    printf("total remote dsentries: %d\n", remote_dsentries);
+#endif
+
+    return OK;
+}
+
+PRIVATE int deallocate_nonxferred_dsentries(struct _magic_dsentry *first_dsentry, st_counterparts_t *counterparts)
+{
+    struct _magic_dsentry *dsentry = first_dsentry;
+    struct _magic_sentry *local_sentry;
+
+    while (dsentry != NULL) {
+        struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
+        int is_paired_dsentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries);
+        int is_alloc_dsentry = MAGIC_SENTRY_IS_ALLOC(sentry);
+        ST_GET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry);
+
+        if (MAGIC_STATE_EXTF_GET(sentry, ST_TRANSFER_DONE) || !is_alloc_dsentry) {
+            dsentry = dsentry->next;
+            continue;
+        }
+
+        /* Report non-transferred alloc dsentries when requested. */
+        if (is_paired_dsentry && (st_policies & ST_REPORT_NONXFERRED_ALLOCS)) {
+            printf("deallocate_nonxferred_dsentries: Non-transferred dsentry found: ");
+            MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
+            printf("\n");
+        }
+        if (!is_paired_dsentry && (st_policies & ST_REPORT_NONXFERRED_UNPAIRED_ALLOCS)) {
+            printf("deallocate_nonxferred_dsentries: Non-transferred unpaired dsentry found: ");
+            MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
+            printf("\n");
+        }
+
+        if (!is_paired_dsentry) {
+            dsentry = dsentry->next;
+            continue;
+        }
+        assert(local_sentry);
+        if (MAGIC_SENTRY_IS_ALLOC(local_sentry)) {
+            deallocate_local_dsentry(MAGIC_DSENTRY_FROM_SENTRY(local_sentry));
+        }
+        dsentry = dsentry->next;
+    }
+
+    return OK;
+}
+#endif
+
+PRIVATE void deallocate_local_dsentry(struct _magic_dsentry *local_dsentry)
+{
+    int r, dsentry_type;
+    struct _magic_sentry *local_sentry = MAGIC_DSENTRY_TO_SENTRY(local_dsentry);
+
+    assert(MAGIC_SENTRY_IS_ALLOC(local_sentry));
+    dsentry_type = MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_OUT_OF_BAND) ? MAGIC_STATE_OUT_OF_BAND : MAGIC_STATE_REGION(local_sentry);
+    /* A MAP_SHARED region will have both MAGIC_STATE_MAP and MAGIC_STATE_SHM. */
+    if (dsentry_type == (MAGIC_STATE_MAP | MAGIC_STATE_SHM))
+        dsentry_type = MAGIC_STATE_MAP;
+
+    MAGIC_MEM_WRAPPER_BEGIN();
+    switch (dsentry_type) {
+        case MAGIC_STATE_HEAP:
+            /* free */
+            magic_free(local_sentry->address);
+            break;
+
+        case MAGIC_STATE_MAP:
+            /* munmap */
+            r = magic_munmap(local_sentry->address, local_sentry->type->size);
+            if (r != 0) {
+                printf("Warning: magic_munmap failed for ");
+                MAGIC_DSENTRY_PRINT(local_dsentry, 0);
+                printf("\n");
+            }
+            break;
+
+#ifndef __MINIX
+        case MAGIC_STATE_SHM:
+            /* shmdt */
+            r = magic_shmdt(local_sentry->address);
+            if (r != 0) {
+                printf("Warning: magic_shmdt failed for ");
+                MAGIC_DSENTRY_PRINT(local_dsentry, 0);
+                printf("\n");
+            }
+            break;
+#endif
+
+        case MAGIC_STATE_OUT_OF_BAND:
+            /* out-of-band dsentry. */
+            r = magic_destroy_obdsentry_by_addr(local_sentry->address);
+            if (r != 0) {
+                printf("Warning: magic_destroy_obdsentry_by_addr failed for ");
+                MAGIC_DSENTRY_PRINT(local_dsentry, 0);
+                printf("\n");
+            }
+            break;
+
+        default:
+            st_cbs_os.panic("ERROR. UNSUPPORTED DSENTRY TYPE: %d\n", dsentry_type);
+    }
+    MAGIC_MEM_WRAPPER_END();
+}
+
+PRIVATE int allocate_local_dsentry(st_init_info_t *info, struct _magic_dsindex *local_dsindex, int num_elements, int is_type_mismatch, const union __alloc_flags *p_alloc_flags, struct _magic_dsentry** local_dsentry_ptr, struct _magic_dsentry *cached_dsentry, void *ptr)
+{
+    struct _magic_dsentry *local_dsentry = NULL;
+    struct _magic_sentry *cached_sentry = NULL;
+    char *name, *parent_name;
+    struct _magic_type *type;
+    int region;
+    size_t size;
+    union __alloc_flags alloc_flags;
+
+    /* Either a dsindex or a dsentry needs to be set. */
+    assert(local_dsindex || cached_dsentry);
+
+    if (cached_dsentry)
+        cached_sentry = MAGIC_DSENTRY_TO_SENTRY(cached_dsentry);
+
+    /* name, parent_name: local_dsindex || cached_dsentry. */
+    if (local_dsindex) {
+        assert(MAGIC_DSINDEX_IS_ALLOC(local_dsindex));
+        name = local_dsindex->name;
+        parent_name = local_dsindex->parent_name;
+    } else {
+        assert(MAGIC_SENTRY_IS_ALLOC(cached_sentry));
+        /*
+         * The external allocation parent_name needs to be readjusted.
+         * The external allocation name is adjusted after the new dsentry
+         * is created.
+         */
+        name = cached_sentry->name;
+        if (!strcmp(cached_dsentry->parent_name, MAGIC_ALLOC_EXT_PARENT_NAME)) {
+            parent_name = MAGIC_ALLOC_EXT_PARENT_NAME;
+        } else {
+            int found_parent_name = 0;
+            struct _magic_sodesc *sodesc;
+            struct _magic_dsodesc *dsodesc;
+            MAGIC_DSODESC_LOCK();
+            MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc,
+                if (!strcmp(cached_dsentry->parent_name, sodesc->lib.name)) {
+                    parent_name = (char *)sodesc->lib.name;
+                    found_parent_name = 1;
+                    break;
+                }
+            );
+            if (!found_parent_name) {
+                MAGIC_DSODESC_ITER(_magic_first_dsodesc, dsodesc,
+                    if (!strcmp(cached_dsentry->parent_name, dsodesc->lib.name)) {
+                        parent_name = (char *)dsodesc->lib.name;
+                        found_parent_name = 1;
+                        break;
+                    }
+                );
+            }
+            MAGIC_DSODESC_UNLOCK();
+            assert(found_parent_name && "Invalid parent name for cached dsentry!");
+        }
+    }
+
+    /* num_elements: args || cached_sentry. */
+    if (num_elements <= 0 && cached_sentry) {
+        num_elements = cached_sentry->type->type_id == MAGIC_TYPE_ARRAY ?
+            cached_sentry->type->num_child_types : 1;
+    }
+    assert(num_elements > 0);
+
+    /* alloc_flags: args || cached_dsentry. */
+    if (!p_alloc_flags) {
+        if (cached_dsentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) {
+            alloc_flags = cached_dsentry->alloc_flags;
+        }
+    } else {
+        alloc_flags = *p_alloc_flags;
+    }
+
+    /* is_type_mismatch: args || cached_dsentry. */
+    if (!is_type_mismatch && cached_dsentry)
+        is_type_mismatch = MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_TYPE_SIZE_MISMATCH);
+
+    /*
+     * Use old address for immutable objects.
+     */
+    /* ptr: args || cached_sentry. */
+    if (!ptr && cached_sentry &&
+            MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_IMMUTABLE))
+        ptr = cached_sentry->address;
+
+    /* region: local_dsindex || cached_sentry. */
+    if (local_dsindex)
+        region = MAGIC_STATE_REGION(local_dsindex);
+    else
+        region = MAGIC_STATE_REGION(cached_sentry);
+
+    /* Check if the region is ambigous. This shouldn't happen. */
+    assert(!((region & (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) ==
+        (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) &&
+        "MAGIC_STATE_HEAP | MAGIC_STATE_MAP detected!");
+#if 0
+    if ((region & (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) ==
+        (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) {
+        /* Check call flags to determine what to do in the ambiguous cases. */
+        region = (alloc_flags.mmap_flags && alloc_flags.mmap_prot) ?
+            MAGIC_STATE_MAP : MAGIC_STATE_HEAP;
+    }
+#endif
+
+    /* type: local_dsindex || cached_sentry. */
+    if (local_dsindex) {
+        type = local_dsindex->type;
+
+        if (num_elements > 1 && MAGIC_TYPE_FLAG(local_dsindex->type, MAGIC_TYPE_VARSIZE)) {
+            size = magic_type_alloc_get_varsized_array_size(local_dsindex->type, num_elements);
+            assert(size > 0);
+        } else {
+            if (is_type_mismatch) {
+                type = MAGIC_VOID_TYPE;
+                printf("WARNING: Type size mismatch dsentry detected! Ignoring dsindex type and reverting to MAGIC_TYPE_VOID.\n");
+                printf("name=%s, parent_name=%s\n", local_dsindex->name, local_dsindex->parent_name);
+            }
+            size = num_elements * type->size;
+        }
+    } else {
+        /*
+         * The type will need adjusting later.
+         */
+        type = cached_sentry->type;
+        size = type->size;
+    }
+
+    *local_dsentry_ptr = NULL;
+
+    if (region & MAGIC_STATE_HEAP) {
+        /* malloc */
+        ptr = magic_malloc_positioned(type, name, parent_name, size, (ptr == NULL ? NULL : MAGIC_PTR_FROM_DATA(ptr)));
+        if (ptr == NULL) {
+            printf("ERROR, magic_malloc_positioned returned NULL.\n");
+            return ENOMEM;
+        }
+        memset(ptr, 0, size);
+        local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr));
+    }
+    else if (region & MAGIC_STATE_MAP) {
+        /* mmap */
+        if (!alloc_flags.mmap_flags || !alloc_flags.mmap_prot) {
+            /* We need call_flags to perform mmap. */
+            return ENOSYS;
+        }
+        ptr = persistent_mmap(type, name, parent_name, info, NULL, size,
+            alloc_flags.mmap_prot, alloc_flags.mmap_flags, -1, 0, ptr);
+        if (ptr == NULL) {
+            printf("ERROR, persistent_mmap returned NULL.\n");
+            return ENOMEM;
+        }
+        if (!(alloc_flags.mmap_flags & MAP_SHARED))
+            memset(ptr, 0, size);
+        local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr));
+    }
+#ifndef __MINIX
+    else if (region & MAGIC_STATE_SHM) {
+        /* shmat */
+        if (!alloc_flags.shmat_flags || !alloc_flags.shmat_shmid) {
+            /* We need call_flags to perform shmat. */
+            return ENOSYS;
+        }
+        ptr = magic_shmat(type, name, parent_name, alloc_flags.shmat_shmid,
+            ptr, alloc_flags.shmat_flags);
+        if (ptr == NULL) {
+            printf("ERROR, magic_shmat returned NULL.\n");
+            return ENOMEM;
+        }
+        local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr));
+    }
+#endif
+    else {
+        if (local_dsindex) {
+            printf("ERROR. UNSUPPORTED DSINDEX TYPE: ");
+            MAGIC_DSINDEX_PRINT(local_dsindex, MAGIC_EXPAND_TYPE_STR);
+        } else {
+            printf("ERROR. UNSUPPORTED DSENTRY: ");
+            MAGIC_DSENTRY_PRINT(cached_dsentry, MAGIC_EXPAND_TYPE_STR);
+        }
+        printf("\n");
+        return EINVAL;
+    }
+
+    if (!local_dsindex) {
+        /*
+         * This was an externally allocated type and, as such, needs adjusting.
+         */
+        assert(cached_sentry->type == &cached_dsentry->type);
+        local_dsentry->type = cached_dsentry->type;
+        if (cached_dsentry->type_array[0]->type_id == MAGIC_TYPE_POINTER) {
+            ST_GET_CACHED_COUNTERPART(cached_dsentry->type_array[0], types, ptr_types, local_dsentry->type_array[0]);
+        } else {
+            ST_GET_CACHED_COUNTERPART(cached_dsentry->type_array[0], types, types, local_dsentry->type_array[0]);
+        }
+        local_dsentry->sentry.type = &local_dsentry->type;
+        local_dsentry->sentry.type->contained_types = local_dsentry->type_array;
+    }
+
+    assert(local_dsentry);
+    assert(local_dsentry->parent_name && strcmp(local_dsentry->parent_name, ""));
+    assert(local_dsentry->sentry.name && strcmp(local_dsentry->sentry.name, ""));
+    assert(magic_check_dsentry(local_dsentry, 0));
+    *local_dsentry_ptr = local_dsentry;
+
+    if (is_type_mismatch)
+        local_dsentry->sentry.flags |= MAGIC_STATE_TYPE_SIZE_MISMATCH;
+
+    /*
+     * Dsentries allocated by shared libraries have the names stored in dsentry
+     * buffers (for now).
+     * Readjust the local_sentry to do this as well, since after state transfer
+     * cleanup the existing names will become invalid.
+     */
+    if (!local_dsindex && MAGIC_SENTRY_IS_LIB_ALLOC(cached_sentry)) {
+        strncpy(local_dsentry->name_ext_buff, local_dsentry->sentry.name,
+            MAGIC_DSENTRY_EXT_NAME_BUFF_SIZE);
+        local_dsentry->sentry.name = local_dsentry->name_ext_buff;
+    }
+
+    return OK;
+}
+
+PRIVATE int check_unpaired_sentry(st_init_info_t *info,
+    struct _magic_sentry* cached_sentry)
+{
+    int sentry_needs_transfer = MAGIC_STATE_EXTF_GET(cached_sentry, ST_NEEDS_TRANSFER | ST_TRANSFER_DONE) == ST_NEEDS_TRANSFER;
+    int report;
+
+    if (!sentry_needs_transfer && !MAGIC_SENTRY_IS_STRING(cached_sentry)) {
+        return OK;
+    }
+
+    if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)) {
+        report = st_policies & ST_REPORT_UNPAIRED_DSENTRIES;
+    }
+    else if(MAGIC_SENTRY_IS_STRING(cached_sentry)) {
+        report = st_policies & ST_REPORT_UNPAIRED_STRINGS;
+    }
+    else {
+        report = st_policies & ST_REPORT_UNPAIRED_SENTRIES;
+    }
+    if (report) {
+        printf("check_unpaired_sentry: Unpaired sentry found: ");
+        ST_SENTRY_PRINT(cached_sentry,MAGIC_EXPAND_TYPE_STR);
+        printf("\n");
+    }
+
+    return OK;
+}
+
+PUBLIC struct _magic_sentry* st_cached_to_remote_sentry(st_init_info_t *info, struct _magic_sentry *cached_sentry)
+{
+    struct _magic_sentry *remote_sentry;
+    void *local_data_addr;
+    ST_CHECK_INIT();
+
+    /* Copy metadata into metadata buffer. */
+    if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)) {
+        magic_copy_dsentry(MAGIC_DSENTRY_FROM_SENTRY(cached_sentry), st_dsentry_buff);
+        remote_sentry = MAGIC_DSENTRY_TO_SENTRY(st_dsentry_buff);
+    }
+    else {
+        memcpy(&st_dsentry_buff->sentry, cached_sentry, sizeof(struct _magic_sentry));
+        remote_sentry = &st_dsentry_buff->sentry;
+    }
+
+    /* Have the remote sentry point to local data. */
+    local_data_addr = NULL;
+    /* See if we have the data locally already first. */
+    ST_GET_CACHED_COUNTERPART(cached_sentry, sentries, sentries_data, local_data_addr);
+    if (!local_data_addr) {
+        /* Copy remote data into local data buffer. */
+        if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) remote_sentry->address
+                , remote_sentry->type->size, (uint32_t) st_data_buff))
+        {
+            printf("ERROR transferring sentry data to local buffer.\n");
+            return NULL;
+        }
+        local_data_addr = st_data_buff;
+    }
+    remote_sentry->address = local_data_addr;
+
+    return remote_sentry;
+}
+
+PRIVATE int transfer_data_sentry(st_init_info_t *info,
+    struct _magic_sentry* cached_sentry)
+{
+
+    int r;
+    int st_cb_flags = ST_CB_DEFAULT_FLAGS;
+    struct _magic_sentry *local_sentry, *remote_sentry;
+    int flags = ST_SEL_ANALYZE_FLAGS;
+    struct st_cb_info cb_info_buff;
+    struct st_cb_info *cb_info = &cb_info_buff;
+    static _magic_selement_t magic_local_selements[MAGIC_MAX_RECURSIVE_TYPES+1];
+    static int magic_flags_by_depth[MAGIC_MAX_RECURSIVE_TYPES+1];
+
+    /* Skip extern weak symbols. */
+    if (!cached_sentry->address) {
+        assert(MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_EXTERNAL));
+        st_set_transfer_status(ST_TRANSFER_DONE, ST_OP_ADD, cached_sentry, NULL);
+        return OK;
+    }
+
+    /* Determine local and remote sentries from the cached version. */
+    local_sentry = NULL;
+    st_lookup_sentry_pair(&cached_sentry, &local_sentry);
+    assert(local_sentry && "Unexpected unpaired sentry!");
+    remote_sentry = st_cached_to_remote_sentry(info, cached_sentry);
+    if (!remote_sentry) {
+        printf("No remote sentry found for cached sentry: ");
+        MAGIC_SENTRY_PRINT(cached_sentry, 0);
+        printf("\n");
+        return EFAULT;
+    }
+
+    cb_info->local_selements = magic_local_selements;
+    cb_info->local_selement = magic_selement_from_sentry(local_sentry, &magic_local_selements[0]);
+    cb_info->walk_flags = MAGIC_TYPE_WALK_DEFAULT_FLAGS;
+    cb_info->st_cb_flags = st_cb_flags;
+    cb_info->init_info = info;
+    cb_info->st_cb_saved_flags = magic_flags_by_depth;
+    magic_flags_by_depth[0] = st_cb_flags;
+
+    EXEC_WITH_MAGIC_VARS(
+        r = magic_sentry_analyze(remote_sentry , flags, transfer_data_selement, cb_info, NULL);
+        , &st_cached_magic_vars
+    );
+    if (r < 0) {
+        return r;
+    }
+
+    st_set_transfer_status(ST_TRANSFER_DONE, ST_OP_ADD, cached_sentry, NULL);
+    return OK;
+}
+
+PRIVATE int transfer_data_selement(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, void *cb_args)
+{
+
+    int r = ST_CB_NOT_PROCESSED;
+    int depth, cb_flags;
+    struct st_cb_info *cb_info = (struct st_cb_info *) cb_args;
+    _magic_selement_t *local_selement, *local_parent_selement;
+    st_cb_selement_transfer_t *cb;
+
+    register_typenames_and_callbacks();
+
+    if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) {
+        depth = selement->depth;
+        local_selement = &cb_info->local_selements[depth];
+        if (depth > 0) {
+            local_parent_selement = &cb_info->local_selements[depth-1];
+            local_selement->sentry = local_parent_selement->sentry;
+            local_selement->parent_type = local_parent_selement->type;
+            local_selement->parent_address = local_parent_selement->address;
+            cb_info->st_cb_flags = cb_info->st_cb_saved_flags[depth-1];
+        }
+        /* Map the cached and the local selement. */
+        st_map_selement(selement, local_selement, cb_info, FALSE);
+        if (local_selement->type == NULL) {
+            /* Unpaired selement. */
+            if (st_policies & ST_REPORT_UNPAIRED_SELEMENTS) {
+                printf("transfer_data_selement: Unpaired selement found: ");
+                MAGIC_SELEMENT_PRINT(selement, MAGIC_EXPAND_TYPE_STR);
+                printf("\n");
+            }
+            return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+        }
+        cb_info->local_selement = local_selement;
+
+        /* See if identity transfer has been requested. */
+        if (cb_info->st_cb_flags & ST_CB_FORCE_IXFER) {
+            r = transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+            assert(r != ST_CB_NOT_PROCESSED);
+            cb_info->st_cb_saved_flags[depth] = cb_info->st_cb_flags;
+            return r;
+        }
+    }
+
+    cb_flags = ST_CB_TYPE_SELEMENT;
+    if (ST_TYPE_NAME_KEY(selement->type) != NULL) {
+        cb_flags |= ST_CB_TYPE_TYPENAME;
+    }
+    if (selement->num == 1) {
+        cb_flags |= ST_CB_TYPE_SENTRY;
+    }
+
+    cb = st_cbs.st_cb_selement_transfer[cb_flags];
+    while (TRUE) {
+
+        if (*cb != NULL) {
+            r = (*cb)(selement, sel_analyzed, sel_stats, cb_info);
+        } else {
+            r = default_transfer_selement_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
+            assert(r != ST_CB_NOT_PROCESSED
+                && "Default selement callback should always process the selement.");
+        }
+
+        if (r != ST_CB_NOT_PROCESSED) {
+            assert((r<0 || MAGIC_SENTRY_ANALYZE_IS_VALID_RET(r)) && "Invalid callback return code!");
+            if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) {
+                cb_info->st_cb_saved_flags[depth] = cb_info->st_cb_flags;
+            }
+            return r;
+        }
+
+        cb++;
+    }
+
+    /* Not reachable. */
+    return EINTR;
+}
+
+PRIVATE int lookup_trg_info(_magic_selement_t *selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info,
+    _magic_selement_t *cached_trg_selement, _magic_selement_t *local_trg_selement)
+{
+    _magic_selement_t *local_selement, *trg_selement;
+    struct _magic_sentry *cached_trg_sentry, *local_trg_sentry = NULL;
+    struct _magic_function *cached_trg_function, *local_trg_function = NULL;
+    _magic_sel_analyzed_t local_sel_analyzed;
+    _magic_sel_stats_t local_sel_stats;
+    void *local_trg_root_address;
+    struct _magic_type *cached_trg_root_type, *local_trg_root_type;
+    int first_legal_trg_type, is_same_type, is_same_trg_type, local_trg_has_addr_not_taken;
+
+    local_selement = cb_info->local_selement;
+    first_legal_trg_type = sel_analyzed->u.ptr.first_legal_trg_type;
+    assert(first_legal_trg_type >= 0);
+    trg_selement = &sel_analyzed->u.ptr.trg_selements[first_legal_trg_type];
+    local_trg_root_type = NULL;
+
+    /* Lookup cached and local targets. */
+    if (MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(sel_analyzed)) {
+        cached_trg_sentry = trg_selement->sentry;
+        local_trg_sentry = NULL;
+        st_lookup_sentry_pair(&cached_trg_sentry, &local_trg_sentry);
+        *cached_trg_selement = *trg_selement;
+        cached_trg_root_type = cached_trg_sentry->type;
+        local_trg_has_addr_not_taken = local_trg_sentry && MAGIC_STATE_FLAG(local_trg_sentry, MAGIC_STATE_ADDR_NOT_TAKEN);
+        local_trg_selement->sentry = local_trg_sentry;
+        if (local_trg_sentry) {
+            local_trg_root_address = local_trg_sentry->address;
+            local_trg_root_type = local_trg_sentry->type;
+        }
+    }
+    else if(MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(sel_analyzed)) {
+        cached_trg_function = MAGIC_DFUNCTION_TO_FUNCTION(&sel_analyzed->u.ptr.trg.dfunction);
+        local_trg_function = NULL;
+        st_lookup_function_pair(&cached_trg_function, &local_trg_function);
+        *cached_trg_selement = *trg_selement;
+        cached_trg_root_type = cached_trg_function->type;
+        local_trg_has_addr_not_taken = local_trg_function && MAGIC_STATE_FLAG(local_trg_function, MAGIC_STATE_ADDR_NOT_TAKEN);
+        local_trg_selement->sentry = NULL;
+        if (local_trg_function) {
+            local_trg_root_address = local_trg_function->address;
+            local_trg_root_type = local_trg_function->type;
+        }
+    }
+
+    /* Check unpaired targets. */
+    if (!local_trg_root_type) {
+        local_trg_selement->type = NULL;
+        return OK;
+    }
+
+    /* Check address not taken violations. */
+    if (local_trg_has_addr_not_taken) {
+        ST_CB_PRINT(ST_CB_ERR, "uncaught ptr with paired target whose address is not taken", selement, sel_analyzed, sel_stats, cb_info);
+        return EFAULT;
+    }
+
+    /* Check types and return immediately in case of perfect pointer match. */
+    is_same_type = selement->type == local_selement->type || ST_PTR_TYPE_IS_CACHED_COUNTERPART(selement->type, local_selement->type);
+    is_same_trg_type = ST_TYPE_IS_CACHED_COUNTERPART(cached_trg_root_type, local_trg_root_type);
+    if (is_same_type && is_same_trg_type) {
+        local_trg_selement->type = cached_trg_selement->type;
+        local_trg_selement->address = (char*) local_trg_root_address + sel_analyzed->u.ptr.trg_offset;
+        return OK;
+    }
+#if CHECK_ASR && !FORCE_SOME_UNPAIRED_TYPES
+    if (cb_info->init_info->flags & ST_LU_ASR) {
+        st_cbs_os.panic("ASR should never get here!");
+    }
+#endif
+
+    /* Map sel_analyzed to its local counterpart. */
+    if (is_same_trg_type) {
+        local_sel_analyzed = *sel_analyzed;
+        local_sel_analyzed.u.ptr.trg_selements[0].address = (char*) local_trg_root_address + sel_analyzed->u.ptr.trg_offset;
+    }
+    else {
+        st_map_sel_analyzed_from_target(sel_analyzed, &local_sel_analyzed, local_trg_sentry, local_trg_function, cb_info);
+        if (local_sel_analyzed.u.ptr.num_trg_types == 0) {
+            /* Unpaired target selements. */
+            local_trg_selement->type = NULL;
+            return OK;
+        }
+    }
+
+    /* Check violations on the local target. */
+    memset(&local_sel_stats, 0, sizeof(local_sel_stats));
+    magic_selement_analyze_ptr_type_invs(local_selement, &local_sel_analyzed, &local_sel_stats);
+    if (MAGIC_SEL_STATS_HAS_VIOLATIONS(&local_sel_stats)) {
+        /* Local pointer with violations found */
+        ST_CB_PRINT(ST_CB_ERR, "uncaught ptr with after-transfer violations", selement, sel_analyzed, sel_stats, cb_info);
+        ST_CB_PRINT(ST_CB_ERR, "transferred ptr with violations", local_selement, &local_sel_analyzed, &local_sel_stats, cb_info);
+        return EFAULT;
+    }
+
+    /* All the targets mapped correctly. */
+    local_trg_selement->type = local_sel_analyzed.u.ptr.trg_selements[0].type;
+    local_trg_selement->address = local_sel_analyzed.u.ptr.trg_selements[0].address;
+    return OK;
+}
+
+/* transfer helper functions */
+
+PRIVATE int md_transfer_str(st_init_info_t *info, char **str_pt)
+{
+    char buff[ST_STR_BUFF_SIZE + 2];
+
+    if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) *str_pt, ST_STR_BUFF_SIZE + 1, (uint32_t) buff)) {
+        st_cbs_os.panic("md_transfer_str(): ERROR transferring string.\n");
+        return EGENERIC;
+    }
+    buff[ST_STR_BUFF_SIZE + 1] = '\0';
+    if (strlen(buff) > ST_STR_BUFF_SIZE) {
+        st_cbs_os.panic("md_transfer_str(): transferred string has a wrong size: %d\n", strlen(buff));
+        return EGENERIC;
+    }
+
+    *str_pt = st_buff_allocate(info, strlen(buff) + 1);
+    if (!*str_pt) {
+        st_cbs_os.panic("md_transfer_str(): string buffer could not be allocated.\n");
+        return EGENERIC;
+    }
+    strcpy(*str_pt, buff);
+    return OK;
+}
+
+PRIVATE int md_transfer(st_init_info_t *info, void *from, void **to, int len)
+{
+    /* backup from value, in case &from == to */
+    void *from_backup = from;
+    *to = st_buff_allocate(info, len);
+    if (!*to) {
+        st_cbs_os.panic("md_transfer(): buffer could not be allocated.\n");
+        return EGENERIC;
+    }
+    if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) from_backup, len, (uint32_t) *to)) {
+        st_cbs_os.panic("md_transfer(): ERROR transferring remote data to buffer.\n");
+        return EGENERIC;
+    }
+    return OK;
+}
+
+
+/* Buffer allocation */
+
+PRIVATE void *persistent_mmap(__MA_ARGS__ st_init_info_t *info, void *start, size_t length, int prot, int flags, int fd, off_t offset, struct _magic_dsentry *dsentry) {
+    if (USE_PRE_ALLOCATED_BUFFER(info)) {
+        size_t alloc_length = length + (length % magic_get_sys_pagesize() == 0 ? 0 : magic_get_sys_pagesize() - (length % magic_get_sys_pagesize()));
+        char *ptr, *data_ptr;
+
+        assert(((char *)info->init_buff_cleanup_start) + alloc_length + magic_get_sys_pagesize() <= st_pre_allocated_page_pt && "mmap region hits temporary buffer.");
+        assert(((char *)info->init_buff_cleanup_start) + alloc_length + magic_get_sys_pagesize() <= ((char *) info->init_buff_start) + info->init_buff_len && "mmap region hits end of pre-allocated buffer");
+
+        ptr = ((char *)info->init_buff_cleanup_start) + magic_get_sys_pagesize() - MAGIC_SIZE_TO_REAL(0);
+        data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, (int) MAGIC_STATE_MAP);
+        MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = flags;
+        MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = prot;
+        info->init_buff_cleanup_start = &data_ptr[alloc_length];
+        return data_ptr;
+    } else {
+        /* no pre-allocated mmap buffer. Call magic_mmap to allocate region. */
+        return magic_mmap_positioned(type, name, parent_name
+            , NULL, length, prot, flags, -1, 0, dsentry);
+    }
+}
+
+PUBLIC void *st_cb_pages_allocate(st_init_info_t *info, uint32_t *phys, int num_pages)
+{
+    void *result;
+    int len = num_pages * magic_get_sys_pagesize();
+
+    if (USE_PRE_ALLOCATED_BUFFER(info)) {
+        if (!st_pre_allocated_page_pt) {
+#if ST_DEBUG_LEVEL > 0
+            printf("st_pages_allocate: initializing pre-allocated page buffer.\n");
+#endif
+            st_pre_allocated_page_pt = &((char *)info->init_buff_start)[info->init_buff_len];
+        }
+        st_pre_allocated_page_pt -= len;
+        assert(st_pre_allocated_page_pt >= (char *)info->init_buff_cleanup_start
+            && "Temporary buffer ran into perminently pre-allocated mmapped pages.");
+        return st_pre_allocated_page_pt;
+    }
+
+    result = st_cbs_os.alloc_contig(len, 0, NULL);
+    if (result == NULL) {
+        printf("st_pages_allocate: alloc_contig(%d) failed.\n", len);
+        return NULL;
+    }
+
+    *phys = (uint32_t) NULL; /* we don't know or need the physical address in order to free */
+
+    return result;
+}
+
+PUBLIC void st_cb_pages_free(st_init_info_t *info, st_alloc_pages *current_page)
+{
+    st_alloc_pages *to_be_freed;
+    int result;
+
+    if (USE_PRE_ALLOCATED_BUFFER(info)) {
+        /* nothing to do */
+        return;
+    }
+
+    while (current_page != NULL) {
+        to_be_freed = current_page;
+        current_page = current_page->previous;
+
+        result = st_cbs_os.free_contig(to_be_freed->virt_addr, to_be_freed->num_pages * magic_get_sys_pagesize());
+
+        if (result != OK) {
+            printf("munmap result != ok, using free()\n");
+            /*
+             * NOTE: in case this is moved out of a magic_* module it needs to be
+             * manually annotated so it doesn't get instrumented.
+             */
+            free(to_be_freed->virt_addr);
+        }
+
+    }
+
+}
+
+PUBLIC void *st_buff_allocate(st_init_info_t *info, size_t size)
+{
+    void *result;
+
+    if (size > st_alloc_buff_available) {
+
+        int pagesize = magic_get_sys_pagesize();
+        uint32_t phys;
+        st_alloc_pages *buff_previous_page = st_alloc_pages_current;
+
+        /* calculate number of pages needed */
+        int pages_needed = (size + sizeof(st_alloc_pages)) / pagesize;
+        if ((size + sizeof(st_alloc_pages)) % pagesize)
+            pages_needed++;
+
+        /* allocate pages */
+        st_alloc_pages_current
+            = st_cbs.st_cb_pages_allocate(info, &phys, pages_needed);
+
+        if (!st_alloc_pages_current) {
+            printf("Could not allocate buffer.\n");
+            return NULL;
+        }
+
+        /* set allocation struct */
+        st_alloc_pages_current->virt_addr = st_alloc_pages_current;
+        st_alloc_pages_current->phys_addr = phys;
+        st_alloc_pages_current->num_pages = pages_needed;
+        st_alloc_pages_current->previous = buff_previous_page;
+
+        /* requested space is right after the struct */
+        st_alloc_buff_pt = (char *) st_alloc_pages_current;
+        st_alloc_buff_pt += sizeof(st_alloc_pages);
+        /* subtract the struct size from the available buffer */
+        st_alloc_buff_available = pages_needed * pagesize - sizeof(st_alloc_pages);
+
+    }
+
+    /* return current buffer pointer */
+    result = st_alloc_buff_pt;
+    /* set buffer pointer after space that is requested, ready for next allocation */
+    st_alloc_buff_pt += size;
+    /* adjust available space */
+    st_alloc_buff_available -= size;
+
+    return result;
+
+}
+
+PUBLIC void st_buff_cleanup(st_init_info_t *info)
+{
+    st_cbs.st_cb_pages_free(info, st_alloc_pages_current);
+    st_alloc_pages_current = NULL;
+    st_alloc_buff_available = 0;
+    st_alloc_buff_pt = NULL;
+}
+
+PUBLIC void st_cleanup(st_init_info_t *info)
+{
+
+#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
+    st_cleanup_rl_index(info, &st_cached_magic_vars);
+    st_cleanup_rl_index(info, _magic_vars);
+#endif
+
+#if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH
+    st_cleanup_sentry_hash(info, &st_cached_magic_vars);
+    st_cleanup_sentry_hash(info, _magic_vars);
+#endif
+
+#if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH
+    st_cleanup_function_hash(info, &st_cached_magic_vars);
+    st_cleanup_function_hash(info, _magic_vars);
+#endif
+
+#if !ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
+    assert(
+        deallocate_nonxferred_dsentries(st_cached_magic_vars.first_dsentry,
+            &st_counterparts) == OK &&
+            "ERROR occurred during call to deallocate_nonxferred_dsentries().");
+#endif
+
+    /*
+     * Free all temporary allocated memory.
+     */
+    st_buff_cleanup(info);
+
+    /*
+     * Reset all values in case of successive state transfers.
+     */
+    st_init_done = FALSE;
+    st_pre_allocated_page_pt = NULL;
+    st_dsentry_buff = NULL;
+    st_data_buff = NULL;
+    st_num_type_transformations = 0;
+    st_local_magic_vars_ptr = &_magic_vars_buff;
+    st_policies = ST_POLICIES_DEFAULT;
+    st_unpaired_types_ratio = ST_UNPAIRED_TYPES_RATIO_DEFAULT;
+    st_unpaired_struct_types_ratio = ST_UNPAIRED_STRUCT_TYPES_RATIO_DEFAULT;
+
+    /* Reallow mempool dsentries lookups. */
+    magic_lookup_nested_dsentries = 1;
+}
+
+/* State cleanup/checking functions. */
+
+/*===========================================================================*
+ *                         do_st_before_receive                              *
+ *===========================================================================*/
+PUBLIC void do_st_before_receive()
+{
+/* Handle State transfer before receive events. */
+  int num_violations;
+
+  assert(st_state_checking_before_receive_is_enabled());
+
+  num_violations = st_do_state_checking();
+  if (__st_before_receive_sc_max_cycles < LONG_MAX) {
+      __st_before_receive_sc_max_cycles--;
+  }
+  if (__st_before_receive_sc_max_violations < LONG_MAX) {
+      __st_before_receive_sc_max_violations -= num_violations;
+  }
+  if (__st_before_receive_sc_max_cycles <= 0) {
+      st_state_checking_before_receive_set_enabled(0, 0, 0);
+      printf("Maximum number of cycles reached\n");
+  }
+  if (__st_before_receive_sc_max_violations <= 0) {
+      st_state_checking_before_receive_set_enabled(0, 0, 0);
+      printf("Maximum number of violations reached\n");
+  }
+}
+
+/*===========================================================================*
+ *                st_state_checking_before_receive_is_enabled                *
+ *===========================================================================*/
+PUBLIC int st_state_checking_before_receive_is_enabled()
+{
+    return __st_before_receive_enabled;
+}
+
+/*===========================================================================*
+ *               st_state_checking_before_receive_set_enabled                *
+ *===========================================================================*/
+PUBLIC int st_state_checking_before_receive_set_enabled(int enabled,
+    int max_cycles, int max_violations)
+{
+    int was_enabled = __st_before_receive_enabled;
+    __st_before_receive_enabled = enabled;
+    if (enabled) {
+        if (max_cycles <= 0) {
+            max_cycles = ST_STATE_CHECKING_DEFAULT_MAX_CYCLES;
+        }
+        if (max_violations <= 0) {
+            max_violations = ST_STATE_CHECKING_DEFAULT_MAX_VIOLATIONS;
+        }
+        __st_before_receive_sc_max_cycles = max_cycles;
+        __st_before_receive_sc_max_violations = max_violations;
+        printf("Continuous state checking enabled, max cycles=%d, max violations=%d\n",
+            max_cycles == LONG_MAX ? 0 : max_cycles,
+            max_violations == LONG_MAX ? 0 : max_violations);
+    }
+    else {
+        printf("Continuous state checking disabled\n");
+    }
+    return was_enabled;
+}
+
+/*===========================================================================*
+ *                         st_cb_state_checking_wrapper                      *
+ *===========================================================================*/
+PRIVATE int st_cb_state_checking_wrapper(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args)
+{
+    struct st_cb_info cb_info_buff;
+    struct st_cb_info *cb_info = &cb_info_buff;
+    int *num_violations = (int*) cb_args;
+    int ret;
+
+    cb_info->local_selements = NULL;
+    cb_info->local_selement = NULL;
+    cb_info->walk_flags = MAGIC_TYPE_WALK_DEFAULT_FLAGS;
+    cb_info->st_cb_flags = ST_CB_CHECK_ONLY;
+    cb_info->st_cb_saved_flags = NULL;
+    cb_info->init_info = NULL;
+
+    ret = transfer_data_selement(selement, sel_analyzed, sel_stats, cb_info);
+    if (ret < 0) {
+        ret = st_cbs.st_cb_state_checking(selement, sel_analyzed, sel_stats, cb_args);
+        (*num_violations)++;
+    }
+    return ret;
+}
+
+/*===========================================================================*
+ *                         st_do_state_checking                              *
+ *===========================================================================*/
+PUBLIC int st_do_state_checking()
+{
+    int num_violations = 0;
+    magic_sentries_analyze(ST_SEL_ANALYZE_FLAGS,
+        st_cb_state_checking_wrapper, &num_violations, NULL);
+    return num_violations;
+}
+
+/*===========================================================================*
+ *                         st_cb_state_checking_null                         *
+ *===========================================================================*/
+PUBLIC int st_cb_state_checking_null(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args)
+{
+    return EINTR;
+}
+
+/*===========================================================================*
+ *                         st_cb_state_checking_print                        *
+ *===========================================================================*/
+PUBLIC int st_cb_state_checking_print(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args)
+{
+    printf("%s. Found state violation:\n", st_cbs_os.debug_header());
+    magic_sentry_print_el_cb(selement, sel_analyzed, sel_stats, cb_args);
+    return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+}
+
+/*===========================================================================*
+ *                         st_cb_state_checking_panic                        *
+ *===========================================================================*/
+PUBLIC int st_cb_state_checking_panic(_magic_selement_t* selement,
+    _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
+    void* cb_args)
+{
+    st_cb_state_checking_print(selement, sel_analyzed, sel_stats, cb_args);
+    st_cbs_os.panic("Time to panic...");
+    return MAGIC_SENTRY_ANALYZE_STOP;
+}
+
+/*===========================================================================*
+ *                         st_do_state_cleanup                               *
+ *===========================================================================*/
+PUBLIC int st_do_state_cleanup()
+{
+    return st_cbs.st_cb_state_cleanup();
+}
+
+/*===========================================================================*
+ *                         st_cb_state_cleanup_null                          *
+ *===========================================================================*/
+PUBLIC int st_cb_state_cleanup_null() {
+    return OK;
+}
+
+#ifndef __MINIX
+/*===========================================================================*
+ *                        st_msync_all_shm_dsentries                         *
+ *===========================================================================*/
+PUBLIC void st_msync_all_shm_dsentries(void) {
+    struct _magic_dsentry *prev_dsentry, *dsentry;
+    struct _magic_sentry *sentry;
+    MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry,
+        dsentry, sentry,
+
+        /*
+         * TODO:
+         * - Don't msync mmaps of /dev/zero
+         */
+        if (MAGIC_STATE_FLAGS(sentry, MAGIC_STATE_SHM | MAGIC_STATE_MAP) &&
+            !(dsentry->alloc_mmap_flags & MAP_ANONYMOUS))
+            msync(MAGIC_PTR_TO_DATA(dsentry), sentry->type->size,
+                MS_SYNC | MS_INVALIDATE);
+
+    );
+}
+#endif
+
diff --git a/minix/llvm/static/magic/minix/magic_ds.c b/minix/llvm/static/magic/minix/magic_ds.c
new file mode 100644 (file)
index 0000000..12cfe5b
--- /dev/null
@@ -0,0 +1,82 @@
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+#include <minix/com.h>
+
+#include <minix/type.h>
+#include <minix/ds.h>
+#include "ds/store.h"
+
+#include <magic_analysis.h>
+#include <st/state_transfer.h>
+
+char* sef_sf_typename_keys[] = { "dsi_u", NULL };
+#define dsi_u_idx 0
+
+/*===========================================================================*
+ *                        sef_cb_sf_transfer_dsi_u                          *
+ *===========================================================================*/
+static int sef_cb_sf_transfer_dsi_u(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) {
+       static struct dsi_mem noxfer_dsi_mem_stub;
+       static const struct _magic_type* _magic_dsi_mem_type = NULL;
+       struct data_store* dsp;
+       _magic_selement_t parent_selement;
+       int ret = EGENERIC;
+       VOLATILE int keep_stubs = (int)&noxfer_dsi_mem_stub;
+       assert(keep_stubs);
+
+       if(magic_selement_get_parent(selement, &parent_selement) == NULL) {
+               ST_CB_PRINT(ST_CB_ERR, "sef_cb_sf_transfer_dsi_u: magic_selement_get_parent failed", selement, sel_analyzed, sel_stats, cb_info);
+               return EINVAL;
+       }
+       dsp = (struct data_store*) parent_selement.address;
+       if(!(dsp->flags & DSF_IN_USE)) {
+               /* Skip when unused. */
+               return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
+       }
+       switch(dsp->flags & DSF_MASK_TYPE) {
+               case DSF_TYPE_U32:
+               case DSF_TYPE_LABEL:
+                       /* Identity transfer when no ptr is involved. */
+                       ret = st_cb_transfer_identity(selement, sel_analyzed, sel_stats, cb_info);
+                       break;
+               case DSF_TYPE_STR:
+               case DSF_TYPE_MEM:
+                       /* Transfer as dsp->u.mem struct. */
+                       if(!_magic_dsi_mem_type && !(_magic_dsi_mem_type = magic_type_lookup_by_name("dsi_mem"))) {
+                               ST_CB_PRINT(ST_CB_ERR, "sef_cb_sf_transfer_dsi_u: type dsi_mem not found", selement, sel_analyzed, sel_stats, cb_info);
+                               return ENOENT;
+                       }
+                       st_cb_selement_type_cast(_magic_dsi_mem_type, _magic_dsi_mem_type, selement, sel_analyzed, sel_stats, cb_info);
+                       ret = st_cb_transfer_selement_generic(selement, sel_analyzed, sel_stats, cb_info);
+                       break;
+               default:
+                       /* Unknown? Report error. */
+                       ST_CB_PRINT(ST_CB_ERR, "sef_cb_sf_transfer_dsi_u: bad flags", selement, sel_analyzed, sel_stats, cb_info);
+                       ret = EFAULT;
+                       break;
+       }
+       return ret;
+}
+
+/*===========================================================================*
+ *                      sef_cb_sf_transfer_typename                         *
+ *===========================================================================*/
+int sef_cb_sf_transfer_typename(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) {
+    const char *typename_key = ST_TYPE_NAME_KEY(selement->type);
+       if(ST_TYPE_NAME_MATCH(sef_sf_typename_keys[dsi_u_idx],typename_key))
+       {
+               return sef_cb_sf_transfer_dsi_u(selement, sel_analyzed, sel_stats, cb_info);
+       }
+
+       return ST_CB_NOT_PROCESSED;
+}
+
+/*===========================================================================*
+ *                      _magic_ds_st_init                         *
+ *===========================================================================*/
+void _magic_ds_st_init(void)
+{
+  st_register_typename_keys(sef_sf_typename_keys);
+  st_setcb_selement_transfer(sef_cb_sf_transfer_typename, ST_CB_TYPE_TYPENAME);
+}
+
diff --git a/minix/llvm/static/magic/minix/magic_util.c b/minix/llvm/static/magic/minix/magic_util.c
new file mode 100644 (file)
index 0000000..0950d94
--- /dev/null
@@ -0,0 +1,103 @@
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <minix/syslib.h>
+#include <minix/sysutil.h>
+
+#include <magic.h>
+#include <magic_mem.h>
+#include <st/state_transfer.h>
+#include <st/special.h>
+
+void *_magic_real_alloc_contig(size_t len, int flags, uint32_t *phys);
+int _magic_real_free_contig(void *addr, size_t len);
+
+
+static char* _magic_generic_debug_header(void)
+{
+    return (char*) "[DEBUG]";
+}
+
+/*===========================================================================*
+ *                         _magic_state_transfer                          *
+ *===========================================================================*/
+int _magic_state_transfer(sef_init_info_t *info)
+{
+    st_init_info_t st_info;
+    /* Convert SEF flags into ST flags. */
+    st_info.flags = 0;
+    if (info->flags & SEF_LU_ASR)
+        st_info.flags |= ST_LU_ASR;
+    if (info->flags & SEF_LU_NOMMAP)
+        st_info.flags |= ST_LU_NOMMAP;
+    st_info.init_buff_start = info->init_buff_start;
+    st_info.init_buff_cleanup_start = info->init_buff_cleanup_start;
+    st_info.init_buff_len = info->init_buff_len;
+    /* Transmit sef_init_info opaquely to the state transfer framework. */
+    st_info.info_opaque = (void *) (info);
+    /* Add the OS callbacks. */
+    st_info.st_cbs_os.panic = &(panic);                                              /* panic() callback. */
+    st_info.st_cbs_os.old_state_table_lookup = &(sef_old_state_table_lookup_opaque); /* old_state_table_lookup() callback. */
+    st_info.st_cbs_os.copy_state_region = &(sef_copy_state_region_opaque);           /* copy_state_region() callback. */
+    st_info.st_cbs_os.alloc_contig = &(_magic_real_alloc_contig);                    /* alloc_contig() callback. */
+    st_info.st_cbs_os.free_contig = &(_magic_real_free_contig);                      /* free_contig() callback. */
+    st_info.st_cbs_os.debug_header = &(_magic_generic_debug_header);                 /* debug_header() callback. */
+    return st_state_transfer(&st_info);
+}
+
+/*===========================================================================*
+ *                             _magic_dump_eval_bool                           *
+ *===========================================================================*/
+void _magic_dump_eval_bool(char *expr)
+{
+    extern char *sef_lu_state_eval;
+    char result;
+    int print_style;
+    (void)(result);
+    print_style = magic_eval_get_print_style();
+    magic_eval_set_print_style(MAGIC_EVAL_PRINT_STYLE_ALL);
+    magic_eval_bool(sef_lu_state_eval, &result);
+    magic_eval_set_print_style(print_style);
+}
+
+/*===========================================================================*
+ *                          _magic_real_alloc_contig                         *
+ *===========================================================================*/
+void *_magic_real_alloc_contig(size_t len, int flags, uint32_t *phys)
+{
+    return magic_real_mmap(NULL, len, PROT_READ|PROT_WRITE,
+        MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+}
+
+/*===========================================================================*
+ *                          _magic_real_free_contig                          *
+ *===========================================================================*/
+int _magic_real_free_contig(void *addr, size_t len)
+{
+    return munmap(addr, len);
+}
+
+/*===========================================================================*
+ *                             _magic_real_brk                            *
+ *===========================================================================*/
+int _magic_real_brk(char *newbrk)
+{
+    return magic_real_brk(newbrk);
+}
+
+/*===========================================================================*
+ *                             _magic_real_mmap                            *
+ *===========================================================================*/
+void* _magic_real_mmap(void *buf, size_t len, int prot, int flags, int fd, off_t offset)
+{
+    return magic_real_mmap(buf, len, prot, flags, fd, offset);
+}
+
+/*===========================================================================*
+ *                              _magic_real_munmap                           *
+ *===========================================================================*/
+int _magic_real_munmap(void *addr, size_t length)
+{
+    return magic_real_munmap(addr, length);
+}