--- /dev/null
+/*
+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 */
--- /dev/null
+/*
+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 */
+
--- /dev/null
+#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);
--- /dev/null
+#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 */
+
--- /dev/null
+#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();
--- /dev/null
+#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
+
--- /dev/null
+#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
+
--- /dev/null
+/* 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
+
--- /dev/null
+#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
+
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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
+
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+/* 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 */
+
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+# 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
--- /dev/null
+#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 $@
+
--- /dev/null
+
+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)
--- /dev/null
+
+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
+
--- /dev/null
+#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");
+}
+
--- /dev/null
+
+#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;
+}
+
--- /dev/null
+#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);
+ }
+}
--- /dev/null
+#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;
+}
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+
+#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
+
--- /dev/null
+#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);
+}
+
+
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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;
+}
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+#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
+
--- /dev/null
+#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);
+}
+
--- /dev/null
+#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);
+}