From: David van Moolenbroek Date: Tue, 30 Jun 2015 16:19:11 +0000 (+0200) Subject: Import magic library from llvm-apps X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=0acd3f1ae0b9c01ddf40d987af41d243c97253c8;p=minix.git Import magic library from llvm-apps Change-Id: Icfbcfae6afc731a23e71448a7a5d0045b2c219e5 --- diff --git a/minix/llvm/include/common/ut/uthash.h b/minix/llvm/include/common/ut/uthash.h new file mode 100644 index 000000000..909cb0ac0 --- /dev/null +++ b/minix/llvm/include/common/ut/uthash.h @@ -0,0 +1,940 @@ +/* +Copyright (c) 2003-2013, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ +#include /* 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 /* 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 to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6 */ +#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hb_keylen=keylen; \ + char *_hb_key=(char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \ + bkt = (hashv) & (num_bkts-1); \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _sx_i; \ + char *_hs_key=(char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + bkt = hashv & (num_bkts-1); \ +} while (0) + +#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _fn_i; \ + char *_hf_key=(char*)(key); \ + hashv = 2166136261UL; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) \ + hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _ho_i; \ + char *_ho_key=(char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned char *_hj_key=(unsigned char*)(key); \ + hashv = 0xfeedbeef; \ + _hj_i = _hj_j = 0x9e3779b9; \ + _hj_k = (unsigned)keylen; \ + while (_hj_k >= 12) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12; \ + } \ + hashv += keylen; \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \ + case 5: _hj_j += _hj_key[4]; \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \ +do { \ + unsigned char *_sfh_key=(unsigned char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = keylen; \ + \ + int _sfh_rem = _sfh_len & 3; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabe; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = (uint32_t)(get16bits (_sfh_key+2)) << 11 ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18); \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + bkt = hashv & (num_bkts-1); \ +} while(0) + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6b; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35l; \ + _h ^= _h >> 16; \ +} while(0) + +#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353; \ + uint32_t _mur_c1 = 0xcc9e2d51; \ + uint32_t _mur_c2 = 0x1b873593; \ + uint32_t _mur_k1 = 0; \ + const uint8_t *_mur_tail; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \ + _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = _mur_h1*5+0xe6546b64; \ + } \ + _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \ + _mur_k1=0; \ + switch((keylen) & 3) { \ + case 3: _mur_k1 ^= _mur_tail[2] << 16; \ + case 2: _mur_k1 ^= _mur_tail[1] << 8; \ + case 1: _mur_k1 ^= _mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ + bkt = hashv & (num_bkts-1); \ +} while(0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* key comparison function; return 0 if keys equal */ +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ +do { \ + if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \ + else out=NULL; \ + while (out) { \ + if ((out)->hh.keylen == keylen_in) { \ + if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \ + } \ + if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \ + else out = NULL; \ + } \ +} while(0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \ + && (addhh)->tbl->noexpand != 1) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while(0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1)) + \ + ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \ + _he_thh; \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1) : 0; \ + if (tbl->ineff_expands > 1) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while(0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) break; \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \ + if (_hs_psize == 0) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0) || !(_hs_q) ) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + _hs_p = (UT_hash_handle*)((_hs_p->next) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail ) { \ + _hs_tail->next = ((_hs_e) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + _hs_e->prev = ((_hs_tail) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + _hs_tail->next = NULL; \ + if ( _hs_nmerges <= 1 ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh) { _last_elt_hh->next = _elt; } \ + if (!dst) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while(0) + +#define HASH_OVERHEAD(hh,head) \ + (size_t)((((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + (sizeof(UT_hash_table)) + \ + (HASH_BLOOM_BYTELEN))) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ + el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL)) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1 +#define HASH_BLOOM_SIGNATURE 0xb12220f2 + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + char bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/minix/llvm/include/common/ut/utlist.h b/minix/llvm/include/common/ut/utlist.h new file mode 100644 index 000000000..6bccec7ad --- /dev/null +++ b/minix/llvm/include/common/ut/utlist.h @@ -0,0 +1,728 @@ +/* +Copyright (c) 2007-2013, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTLIST_H +#define UTLIST_H + +#define UTLIST_VERSION 1.9.8 + +#include + +/* + * This file contains macros to manipulate singly and doubly-linked lists. + * + * 1. LL_ macros: singly-linked lists. + * 2. DL_ macros: doubly-linked lists. + * 3. CDL_ macros: circular doubly-linked lists. + * + * To use singly-linked lists, your structure must have a "next" pointer. + * To use doubly-linked lists, your structure must "prev" and "next" pointers. + * Either way, the pointer to the head of the list must be initialized to NULL. + * + * ----------------.EXAMPLE ------------------------- + * struct item { + * int id; + * struct item *prev, *next; + * } + * + * struct item *list = NULL: + * + * int main() { + * struct item *item; + * ... allocate and populate item ... + * DL_APPEND(list, item); + * } + * -------------------------------------------------- + * + * For doubly-linked lists, the append and delete macros are O(1) + * For singly-linked lists, append and delete are O(n) but prepend is O(1) + * The sort macro is O(n log(n)) for all types of single/double/circular lists. + */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ code), this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#ifdef _MSC_VER /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define LDECLTYPE(x) decltype(x) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define LDECLTYPE(x) char* +#endif +#else /* GNU, Sun and other compilers */ +#define LDECLTYPE(x) __typeof(x) +#endif + +/* for VS2008 we use some workarounds to get around the lack of decltype, + * namely, we always reassign our tmp variable to the list head if we need + * to dereference its prev/next pointers, and save/restore the real head.*/ +#ifdef NO_DECLTYPE +#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } +#define _NEXT(elt,list,next) ((char*)((list)->next)) +#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } +/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ +#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } +#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } +#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } +#else +#define _SV(elt,list) +#define _NEXT(elt,list,next) ((elt)->next) +#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) +/* #define _PREV(elt,list,prev) ((elt)->prev) */ +#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) +#define _RS(list) +#define _CASTASGN(a,b) (a)=(b) +#endif + +/****************************************************************************** + * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * + * Unwieldy variable names used here to avoid shadowing passed-in variables. * + *****************************************************************************/ +#define LL_SORT(list, cmp) \ + LL_SORT2(list, cmp, next) + +#define LL_SORT2(list, cmp, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + _CASTASGN(_ls_p,list); \ + list = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + } else { \ + _CASTASGN(list,_ls_e); \ + } \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ + } \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + + +#define DL_SORT(list, cmp) \ + DL_SORT2(list, cmp, prev, next) + +#define DL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + _CASTASGN(_ls_p,list); \ + list = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + } else { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + } else { \ + _CASTASGN(list,_ls_e); \ + } \ + _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + _CASTASGN(list->prev, _ls_tail); \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +#define CDL_SORT(list, cmp) \ + CDL_SORT2(list, cmp, prev, next) + +#define CDL_SORT2(list, cmp, prev, next) \ +do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + LDECLTYPE(list) _ls_oldhead; \ + LDECLTYPE(list) _tmp; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + _CASTASGN(_ls_p,list); \ + _CASTASGN(_ls_oldhead,list); \ + list = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + _SV(_ls_q,list); \ + if (_NEXT(_ls_q,list,next) == _ls_oldhead) { \ + _ls_q = NULL; \ + } else { \ + _ls_q = _NEXT(_ls_q,list,next); \ + } \ + _RS(list); \ + if (!_ls_q) break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else if (cmp(_ls_p,_ls_q) <= 0) { \ + _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = \ + _NEXT(_ls_p,list,next); _RS(list); _ls_psize--; \ + if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \ + } else { \ + _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = \ + _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \ + } \ + if (_ls_tail) { \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list); \ + } else { \ + _CASTASGN(list,_ls_e); \ + } \ + _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + _CASTASGN(list->prev,_ls_tail); \ + _CASTASGN(_tmp,list); \ + _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping=0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ +} while (0) + +/****************************************************************************** + * singly linked list macros (non-circular) * + *****************************************************************************/ +#define LL_PREPEND(head,add) \ + LL_PREPEND2(head,add,next) + +#define LL_PREPEND2(head,add,next) \ +do { \ + (add)->next = head; \ + head = add; \ +} while (0) + +#define LL_CONCAT(head1,head2) \ + LL_CONCAT2(head1,head2,next) + +#define LL_CONCAT2(head1,head2,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head1) { \ + _tmp = head1; \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(head2); \ + } else { \ + (head1)=(head2); \ + } \ +} while (0) + +#define LL_APPEND(head,add) \ + LL_APPEND2(head,add,next) + +#define LL_APPEND2(head,add,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + (add)->next=NULL; \ + if (head) { \ + _tmp = head; \ + while (_tmp->next) { _tmp = _tmp->next; } \ + _tmp->next=(add); \ + } else { \ + (head)=(add); \ + } \ +} while (0) + +#define LL_DELETE(head,del) \ + LL_DELETE2(head,del,next) + +#define LL_DELETE2(head,del,next) \ +do { \ + LDECLTYPE(head) _tmp; \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + _tmp = head; \ + while (_tmp->next && (_tmp->next != (del))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = ((del)->next); \ + } \ + } \ +} while (0) + +/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ +#define LL_APPEND_VS2008(head,add) \ + LL_APPEND2_VS2008(head,add,next) + +#define LL_APPEND2_VS2008(head,add,next) \ +do { \ + if (head) { \ + (add)->next = head; /* use add->next as a temp variable */ \ + while ((add)->next->next) { (add)->next = (add)->next->next; } \ + (add)->next->next=(add); \ + } else { \ + (head)=(add); \ + } \ + (add)->next=NULL; \ +} while (0) + +#define LL_DELETE_VS2008(head,del) \ + LL_DELETE2_VS2008(head,del,next) + +#define LL_DELETE2_VS2008(head,del,next) \ +do { \ + if ((head) == (del)) { \ + (head)=(head)->next; \ + } else { \ + char *_tmp = (char*)(head); \ + while ((head)->next && ((head)->next != (del))) { \ + head = (head)->next; \ + } \ + if ((head)->next) { \ + (head)->next = ((del)->next); \ + } \ + { \ + char **_head_alias = (char**)&(head); \ + *_head_alias = _tmp; \ + } \ + } \ +} while (0) +#ifdef NO_DECLTYPE +#undef LL_APPEND +#define LL_APPEND LL_APPEND_VS2008 +#undef LL_DELETE +#define LL_DELETE LL_DELETE_VS2008 +#undef LL_DELETE2 +#define LL_DELETE2_VS2008 +#undef LL_APPEND2 +#define LL_APPEND2 LL_APPEND2_VS2008 +#undef LL_CONCAT /* no LL_CONCAT_VS2008 */ +#undef DL_CONCAT /* no DL_CONCAT_VS2008 */ +#endif +/* end VS2008 replacements */ + +#define LL_FOREACH(head,el) \ + LL_FOREACH2(head,el,next) + +#define LL_FOREACH2(head,el,next) \ + for(el=head;el;el=(el)->next) + +#define LL_FOREACH_SAFE(head,el,tmp) \ + LL_FOREACH_SAFE2(head,el,tmp,next) + +#define LL_FOREACH_SAFE2(head,el,tmp,next) \ + for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) + +#define LL_SEARCH_SCALAR(head,out,field,val) \ + LL_SEARCH_SCALAR2(head,out,field,val,next) + +#define LL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while(0) + +#define LL_SEARCH(head,out,elt,cmp) \ + LL_SEARCH2(head,out,elt,cmp,next) + +#define LL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + LL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while(0) + +#define LL_REPLACE_ELEM(head, el, add) \ +do { \ + LDECLTYPE(head) _tmp; \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el)->next; \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = head; \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ +} while (0) + +#define LL_PREPEND_ELEM(head, el, add) \ +do { \ + LDECLTYPE(head) _tmp; \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = head; \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ +} while (0) \ + + +/****************************************************************************** + * doubly linked list macros (non-circular) * + *****************************************************************************/ +#define DL_PREPEND(head,add) \ + DL_PREPEND2(head,add,prev,next) + +#define DL_PREPEND2(head,add,prev,next) \ +do { \ + (add)->next = head; \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev = (add); \ + } else { \ + (add)->prev = (add); \ + } \ + (head) = (add); \ +} while (0) + +#define DL_APPEND(head,add) \ + DL_APPEND2(head,add,prev,next) + +#define DL_APPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev->next = (add); \ + (head)->prev = (add); \ + (add)->next = NULL; \ + } else { \ + (head)=(add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ +} while (0) + +#define DL_CONCAT(head1,head2) \ + DL_CONCAT2(head1,head2,prev,next) + +#define DL_CONCAT2(head1,head2,prev,next) \ +do { \ + LDECLTYPE(head1) _tmp; \ + if (head2) { \ + if (head1) { \ + _tmp = (head2)->prev; \ + (head2)->prev = (head1)->prev; \ + (head1)->prev->next = (head2); \ + (head1)->prev = _tmp; \ + } else { \ + (head1)=(head2); \ + } \ + } \ +} while (0) + +#define DL_DELETE(head,del) \ + DL_DELETE2(head,del,prev,next) + +#define DL_DELETE2(head,del,prev,next) \ +do { \ + assert((del)->prev != NULL); \ + if ((del)->prev == (del)) { \ + (head)=NULL; \ + } else if ((del)==(head)) { \ + (del)->next->prev = (del)->prev; \ + (head) = (del)->next; \ + } else { \ + (del)->prev->next = (del)->next; \ + if ((del)->next) { \ + (del)->next->prev = (del)->prev; \ + } else { \ + (head)->prev = (del)->prev; \ + } \ + } \ +} while (0) + + +#define DL_FOREACH(head,el) \ + DL_FOREACH2(head,el,next) + +#define DL_FOREACH2(head,el,next) \ + for(el=head;el;el=(el)->next) + +/* this version is safe for deleting the elements during iteration */ +#define DL_FOREACH_SAFE(head,el,tmp) \ + DL_FOREACH_SAFE2(head,el,tmp,next) + +#define DL_FOREACH_SAFE2(head,el,tmp,next) \ + for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) + +/* these are identical to their singly-linked list counterparts */ +#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR +#define DL_SEARCH LL_SEARCH +#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 +#define DL_SEARCH2 LL_SEARCH2 + +#define DL_REPLACE_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + (add)->next = (el)->next; \ + if ((el)->next == NULL) { \ + (add)->prev = (add); \ + } else { \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + } \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->prev->next = (add); \ + if ((el)->next == NULL) { \ + (head)->prev = (add); \ + } else { \ + (add)->next->prev = (add); \ + } \ + } \ +} while (0) + +#define DL_PREPEND_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->prev->next = (add); \ + } \ +} while (0) \ + + +/****************************************************************************** + * circular doubly linked list macros * + *****************************************************************************/ +#define CDL_PREPEND(head,add) \ + CDL_PREPEND2(head,add,prev,next) + +#define CDL_PREPEND2(head,add,prev,next) \ +do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + } \ +(head)=(add); \ +} while (0) + +#define CDL_DELETE(head,del) \ + CDL_DELETE2(head,del,prev,next) + +#define CDL_DELETE2(head,del,prev,next) \ +do { \ + if ( ((head)==(del)) && ((head)->next == (head))) { \ + (head) = 0L; \ + } else { \ + (del)->next->prev = (del)->prev; \ + (del)->prev->next = (del)->next; \ + if ((del) == (head)) (head)=(del)->next; \ + } \ +} while (0) + +#define CDL_FOREACH(head,el) \ + CDL_FOREACH2(head,el,next) + +#define CDL_FOREACH2(head,el,next) \ + for(el=head;el;el=((el)->next==head ? 0L : (el)->next)) + +#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ + CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) + +#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next) \ + for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ + (el) && ((tmp2)=(el)->next, 1); \ + ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) + +#define CDL_SEARCH_SCALAR(head,out,field,val) \ + CDL_SEARCH_SCALAR2(head,out,field,val,next) + +#define CDL_SEARCH_SCALAR2(head,out,field,val,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((out)->field == (val)) break; \ + } \ +} while(0) + +#define CDL_SEARCH(head,out,elt,cmp) \ + CDL_SEARCH2(head,out,elt,cmp,next) + +#define CDL_SEARCH2(head,out,elt,cmp,next) \ +do { \ + CDL_FOREACH2(head,out,next) { \ + if ((cmp(out,elt))==0) break; \ + } \ +} while(0) + +#define CDL_REPLACE_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + if ((el)->next == (el)) { \ + (add)->next = (add); \ + (add)->prev = (add); \ + (head) = (add); \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } \ +} while (0) + +#define CDL_PREPEND_ELEM(head, el, add) \ +do { \ + assert(head != NULL); \ + assert(el != NULL); \ + assert(add != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ +} while (0) \ + +#endif /* UTLIST_H */ + diff --git a/minix/llvm/include/magic.h b/minix/llvm/include/magic.h new file mode 100644 index 000000000..9bbca57f4 --- /dev/null +++ b/minix/llvm/include/magic.h @@ -0,0 +1,1209 @@ +#ifndef _MAGIC_H +#define _MAGIC_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* Magic type macros. */ +#define MAGIC_TYPE_WALK_STOP 1 +#define MAGIC_TYPE_WALK_SKIP_PATH 2 +#define MAGIC_TYPE_WALK_CONTINUE 3 + +#define MAGIC_TYPE_WALK_UNIONS_AS_VOID 0x1 +#define MAGIC_TYPE_WALK_DEFAULT_FLAGS (MAGIC_TYPE_WALK_UNIONS_AS_VOID) + +#define MAGIC_TYPE_COMPARE_VALUE_SET 0x01 +#define MAGIC_TYPE_COMPARE_FLAGS 0x02 +#define MAGIC_TYPE_COMPARE_NAME 0x04 +#define MAGIC_TYPE_COMPARE_NAMES 0x08 +#define MAGIC_TYPE_COMPARE_MEMBER_NAMES 0x10 +#define MAGIC_TYPE_COMPARE_MEMBER_OFFSETS 0x20 +#define MAGIC_TYPE_COMPARE_ALL (MAGIC_TYPE_COMPARE_VALUE_SET | \ + MAGIC_TYPE_COMPARE_FLAGS | MAGIC_TYPE_COMPARE_NAME | \ + MAGIC_TYPE_COMPARE_NAMES | MAGIC_TYPE_COMPARE_MEMBER_NAMES | \ + MAGIC_TYPE_COMPARE_MEMBER_OFFSETS) + +#define MAGIC_TYPE_IS_WALKABLE(T) ((T)->type_id == MAGIC_TYPE_ARRAY \ + || (T)->type_id == MAGIC_TYPE_VECTOR || (T)->type_id == MAGIC_TYPE_UNION \ + || (T)->type_id == MAGIC_TYPE_STRUCT) +#define MAGIC_TYPE_NUM_CONTAINED_TYPES(T) \ + ((T)->type_id == MAGIC_TYPE_ARRAY ? 1 : (T)->num_child_types) + +#define MAGIC_TYPE_IS_VOID(T) ((T)->type_id == MAGIC_TYPE_VOID \ + || ( ((T)->flags & MAGIC_TYPE_EXTERNAL) && !strcmp((T)->type_str, "i8") )) +#define MAGIC_TYPE_IS_RAW_ARRAY(T) \ + (((T)->type_id == MAGIC_TYPE_ARRAY \ + && (T)->contained_types[0]->type_id == MAGIC_TYPE_VOID) \ + || (T)->type_id == MAGIC_TYPE_UNION) +#define MAGIC_TYPE_IS_INT_ARRAY(T) \ + ((T)->type_id == MAGIC_TYPE_ARRAY \ + && (T)->contained_types[0]->type_id == MAGIC_TYPE_INTEGER) + +#define MAGIC_EXPAND_TYPE_STR 0x1 +#define MAGIC_SKIP_COMP_TYPES 0x2 +#define MAGIC_EXPAND_SENTRY 0x4 + +#define MAGIC_TYPE_STR_PRINT_LLVM_TYPES 0x01 +#define MAGIC_TYPE_STR_PRINT_SOURCE_TYPES 0x02 +#define MAGIC_TYPE_STR_PRINT_MEMBER_NAMES 0x04 +#define MAGIC_TYPE_STR_PRINT_SKIP_UNIONS 0x08 +#define MAGIC_TYPE_STR_PRINT_SKIP_STRUCTS 0x10 +#define MAGIC_TYPE_STR_PRINT_MULTI_NAMES 0x20 +#define MAGIC_TYPE_STR_PRINT_STYLE_DEFAULT \ + (MAGIC_TYPE_STR_PRINT_LLVM_TYPES | MAGIC_TYPE_STR_PRINT_SOURCE_TYPES | \ + MAGIC_TYPE_STR_PRINT_MEMBER_NAMES) + +#define MAGIC_TYPE_STR_PRINT_DEBUG MAGIC_DEBUG_SET(0) + +#define MAGIC_TYPE_HAS_COMP_TYPES(T) ((T)->compatible_types != NULL) +#define MAGIC_TYPE_HAS_COMP_TYPE(T, I) \ + ((T)->compatible_types[(I)] != NULL) +#define MAGIC_TYPE_COMP_TYPE(T, I) ((T)->compatible_types[(I)]) +#define MAGIC_TYPE_NUM_COMP_TYPES(T, NUM) \ + do { \ + *(NUM) = 0; \ + while(MAGIC_TYPE_HAS_COMP_TYPE(T, (*(NUM))++)); \ + (*(NUM))--; \ + } while(0) +#define MAGIC_TYPE_HAS_VALUE_SET(T) ((T)->value_set != NULL) +#define MAGIC_TYPE_HAS_VALUE(T, I) ((I) < ((int*)(T)->value_set)[0]) +#define MAGIC_TYPE_VALUE(T, I) (((int*)(T)->value_set)[(I)+1]) +#define MAGIC_TYPE_NUM_VALUES(T, NUM) (*(NUM) = ((int*)(T)->value_set)[0]) +#define MAGIC_TYPE_HAS_MULTI_NAMES(T) ((T)->num_names > 1) + +#define MAGIC_TYPE_FLAG(T,F) (((T)->flags & (F)) != 0) +#define MAGIC_TYPE_ID(T) ((T)->id) +#define MAGIC_TYPE_IS_STRING(T) (MAGIC_TYPE_FLAG(T,MAGIC_TYPE_EXTERNAL) \ + && (T)->type_id == MAGIC_TYPE_ARRAY \ + && !strcmp((T)->contained_types[0]->type_str, "i8")) +#define MAGIC_TYPE_PRINT(T, FLAGS) do { \ + _magic_printf("TYPE: (id=%5d, name=%s, size=%d, num_child_types=%d, " \ + "type_id=%d, bit_width=%d, flags(ERDIVvUP)=%d%d%d%d%d%d%d%d, " \ + "values='", MAGIC_TYPE_ID(T), (T)->name, (T)->size, \ + (T)->num_child_types, (T)->type_id, (T)->bit_width, \ + MAGIC_TYPE_FLAG(T,MAGIC_TYPE_EXTERNAL), \ + MAGIC_TYPE_FLAG(T,MAGIC_TYPE_IS_ROOT), \ + MAGIC_TYPE_FLAG(T,MAGIC_TYPE_DYNAMIC), \ + MAGIC_TYPE_FLAG(T,MAGIC_TYPE_INT_CAST), \ + MAGIC_TYPE_FLAG(T,MAGIC_TYPE_STRICT_VALUE_SET), \ + MAGIC_TYPE_FLAG(T,MAGIC_TYPE_VARSIZE), \ + MAGIC_TYPE_FLAG(T,MAGIC_TYPE_UNSIGNED), \ + MAGIC_TYPE_FLAG(T,MAGIC_TYPE_NO_INNER_PTRS)); \ + if(MAGIC_TYPE_HAS_VALUE_SET(T)) magic_type_values_print(T); \ + if(MAGIC_TYPE_HAS_MULTI_NAMES(T)) { \ + _magic_printf("', names='"); \ + magic_type_names_print(T); \ + } \ + _magic_printf("', type_str="); \ + if((FLAGS) & MAGIC_EXPAND_TYPE_STR) magic_type_str_print(T); \ + else _magic_printf("%s", (T)->type_str ? (T)->type_str : ""); \ + if(MAGIC_TYPE_HAS_COMP_TYPES(T)) { \ + _magic_printf(", comp_types=("); \ + magic_type_comp_types_print(T, FLAGS); \ + _magic_printf(")"); \ + } \ + _magic_printf(")"); \ + } while(0) + +#define MAGIC_TYPE_VARSIZE_EL_TYPE(T) \ + (T)->contained_types[(T)->num_child_types - 1]->contained_types[0] + +#define MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(AT,T,CT,S,VSN) do { \ + assert(((S) && ((S) % (T)->size == 0 || VSN)) && "Bad size!"); \ + (AT)->id = MAGIC_ID_NONE; \ + (AT)->flags |= MAGIC_TYPE_DYNAMIC; \ + (AT)->type_id = MAGIC_TYPE_ARRAY; \ + (AT)->size = S; \ + (AT)->num_child_types = (S)/(T)->size; \ + (AT)->contained_types = CT; \ + (AT)->contained_types[0] = T; \ + if(VSN) { \ + (AT)->flags |= MAGIC_TYPE_VARSIZE; \ + (AT)->num_child_types = VSN; \ + } \ + } while(0) +#define MAGIC_TYPE_ARRAY_CREATE_FROM_N(AT,T,CT,N) \ + MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(AT,T,CT,(T)->size*N, 0) + +#define MAGIC_TYPE_VOID_ARRAY_GET_FROM_SIZE(AT,S) do { \ + *(AT) = *MAGIC_VOID_ARRAY_TYPE; \ + MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(AT,MAGIC_VOID_TYPE, \ + MAGIC_VOID_ARRAY_TYPE->contained_types,S,0); \ + } while(0) +#define MAGIC_TYPE_VOID_ARRAY_GET_FROM_N(AT,N) \ + MAGIC_TYPE_VOID_ARRAY_GET_FROM_SIZE(AT,MAGIC_VOID_TYPE->size*N) + +#define MAGIC_TYPE_PTRINT_ARRAY_GET_FROM_SIZE(AT,S) do { \ + *(AT) = *MAGIC_PTRINT_ARRAY_TYPE; \ + MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(AT,MAGIC_PTRINT_TYPE, \ + MAGIC_PTRINT_ARRAY_TYPE->contained_types,S,0); \ + } while(0) +#define MAGIC_TYPE_PTRINT_ARRAY_GET_FROM_N(AT,N) \ + MAGIC_TYPE_PTRINT_ARRAY_GET_FROM_SIZE(AT,MAGIC_PTRINT_TYPE->size*N) + +#define MAGIC_TYPE_INT_CREATE(T,S,N,B) do { \ + (T)->id = MAGIC_ID_NONE; \ + (T)->flags |= MAGIC_TYPE_DYNAMIC; \ + (T)->type_id = MAGIC_TYPE_INTEGER; \ + (T)->size = S; \ + (T)->num_child_types = 0; \ + (T)->contained_types = NULL; \ + (T)->bit_width = (S)*8; \ + (T)->name = N; \ + sprintf(B, "i%d", (T)->bit_width); \ + (T)->type_str = B; \ + } while(0) + +#define MAGIC_TYPE_COMP_ITER(TYPE,COMP_TYPE,DO) do { \ + if(MAGIC_TYPE_HAS_COMP_TYPES(TYPE)) { \ + int __i = 0; \ + while(MAGIC_TYPE_HAS_COMP_TYPE(TYPE, __i)) { \ + COMP_TYPE=MAGIC_TYPE_COMP_TYPE(TYPE, __i); \ + DO \ + __i++; \ + } \ + } \ + } while(0) + +/* Magic function macros. */ +#define MAGIC_FUNCTION_PARENT(F) \ + (MAGIC_STATE_FLAG(F,MAGIC_STATE_DYNAMIC) ? \ + MAGIC_DFUNCTION_FROM_FUNCTION(F)->parent_name : "") +#define MAGIC_FUNCTION_ID(F) ((F)->id) +#define MAGIC_FUNCTION_PRINT(F, EXPAND_TYPE_STR) do { \ + _magic_printf("FUNCTION: (id=%5lu, name=%s, parent=%s, address=0x%08x,"\ + " flags(RLDCdTArwxEI)=%c%c%d%d%d%d%d%d%d%d%d%d, type=", \ + (unsigned long)MAGIC_FUNCTION_ID(F), (F)->name, \ + MAGIC_FUNCTION_PARENT(F), (unsigned) (F)->address, \ + MAGIC_STATE_REGION_C(F), MAGIC_STATE_LIBSPEC_C(F), \ + MAGIC_STATE_FLAG(F,MAGIC_STATE_DIRTY), \ + MAGIC_STATE_FLAG(F,MAGIC_STATE_CONSTANT), \ + MAGIC_STATE_FLAG(F,MAGIC_STATE_DYNAMIC), \ + MAGIC_STATE_FLAG(F,MAGIC_STATE_DETACHED), \ + MAGIC_STATE_FLAG(F,MAGIC_STATE_ADDR_NOT_TAKEN), \ + MAGIC_STATE_FLAG(F,MAGIC_STATE_MODE_R), \ + MAGIC_STATE_FLAG(F,MAGIC_STATE_MODE_W), \ + MAGIC_STATE_FLAG(F,MAGIC_STATE_MODE_X), \ + MAGIC_STATE_FLAG(F,MAGIC_STATE_EXTERNAL), \ + MAGIC_STATE_FLAG(F,MAGIC_STATE_IMMUTABLE)); \ + MAGIC_TYPE_PRINT((F)->type, EXPAND_TYPE_STR); \ + _magic_printf(")"); \ + } while(0) + +/* Magic function hash macros. */ +#define MAGIC_FUNCTION_TO_HASH_EL(function, function_hash) \ + do { \ + function_hash->key = function->address; \ + function_hash->function = function; \ + } while (0) + +#define MAGIC_DFUNCTION_TO_HASH_EL(dfunction, function, function_hash) \ + do { \ + function_hash->key = function->address; \ + function_hash->function = function; \ + } while (0) + +/* Estimated maximum number of buckets needed. Increase as necessary. */ +#define MAGIC_FUNCTION_ADDR_EST_MAX_BUCKETS 32768 +/* + * Since we don't support freeing memory, we need to allocate _all_ the + * intermediate buckets as well. For simplicity, just assume 1 + 2 + 4 + ... + * + 2^n, though it will probably be less than that. + */ +#define MAGIC_FUNCTION_ADDR_EST_TOTAL_BUCKETS \ + ((MAGIC_FUNCTION_ADDR_EST_MAX_BUCKETS << 1) - 1) +#define MAGIC_FUNCTION_ADDR_HASH_OVERHEAD \ + (MAGIC_FUNCTION_ADDR_EST_TOTAL_BUCKETS * sizeof(UT_hash_bucket) + \ + sizeof(UT_hash_table)) + +/* Magic dynamic function macros. */ +#define MAGIC_DFUNCTION_PREV(DF) ((DF)->prev) +#define MAGIC_DFUNCTION_HAS_PREV(DF) ((DF)->prev != NULL) +#define MAGIC_DFUNCTION_NEXT(DF) ((DF)->next) +#define MAGIC_DFUNCTION_HAS_NEXT(DF) ((DF)->next != NULL) +#define MAGIC_DFUNCTION_TO_FUNCTION(DF) (&((DF)->function)) +#define MAGIC_DFUNCTION_FROM_FUNCTION(F) \ + ((struct _magic_dfunction*)(((char*)(F)) - \ + offsetof(struct _magic_dfunction, function))) + +#define MAGIC_DFUNCTION_MNUM (~(0xFEE1DEAF)) +#define MAGIC_DFUNCTION_MNUM_NULL 0 + +#define MAGIC_DFUNCTION_MNUM_OK(D) ((D)->magic_number == MAGIC_DFUNCTION_MNUM) + +#define MAGIC_DFUNCTION_PRINT(DF, EXPAND_TYPE_STR) do { \ + _magic_printf("DFUNCTION: (~mnum=%08x, address=0x%08x, prev=0x%08x, " \ + "next=0x%08x, function=", ~((DF)->magic_number), (unsigned) (DF), \ + (unsigned) (DF)->prev, (unsigned) (DF)->next); \ + MAGIC_FUNCTION_PRINT(MAGIC_DFUNCTION_TO_FUNCTION(DF), EXPAND_TYPE_STR);\ + _magic_printf(")"); \ + } while(0) + +#define MAGIC_DFUNCTION_ITER(HEAD, DFUNC, DO) do { \ + if(HEAD) { \ + DFUNC = NULL; \ + while(!DFUNC || MAGIC_DFUNCTION_HAS_NEXT(DFUNC)) { \ + DFUNC = !DFUNC ? HEAD : MAGIC_DFUNCTION_NEXT(DFUNC); \ + assert(magic_check_dfunction(DFUNC, 0) \ + && "Bad magic dfunction looked up!"); \ + DO \ + } \ + } \ + } while(0) + +#define MAGIC_DFUNCTION_FUNC_ITER(HEAD, DFUNC, FUNC, DO) \ + MAGIC_DFUNCTION_ITER(HEAD, DFUNC, \ + FUNC = MAGIC_DFUNCTION_TO_FUNCTION(DFUNC); \ + DO \ + ); + +/* Magic dynamic state index macros. */ +#define MAGIC_DSINDEX_ID(I) ((I) - _magic_dsindexes + 1) +#define MAGIC_DSINDEX_IS_ALLOC(I) \ + ((I) && !MAGIC_STATE_FLAG(I, MAGIC_STATE_STACK)) +#define MAGIC_DSINDEX_PRINT(I, EXPAND_TYPE_STR) do { \ + _magic_printf("DSINDEX: (id=%5d, name=%s, parent=%s, " \ + "flags(SHMs)=%d%d%d%d type=", \ + MAGIC_DSINDEX_ID(I), (I)->name, (I)->parent_name, \ + MAGIC_STATE_FLAG((I), MAGIC_STATE_STACK), MAGIC_STATE_FLAG((I), \ + MAGIC_STATE_HEAP), MAGIC_STATE_FLAG((I), MAGIC_STATE_MAP), \ + MAGIC_STATE_FLAG((I), MAGIC_STATE_SHM)); \ + MAGIC_TYPE_PRINT((I)->type, EXPAND_TYPE_STR); \ + _magic_printf(")"); \ + } while(0) + +/* Magic dynamic state entry macros. */ +#define MAGIC_DSENTRY_PREV(DE) ((DE)->prev) +#define MAGIC_DSENTRY_HAS_PREV(DE) ((DE)->prev != NULL) +#define MAGIC_DSENTRY_NEXT(DE) ((DE)->next) +#define MAGIC_DSENTRY_HAS_NEXT(DE) ((DE)->next != NULL) +#define MAGIC_DSENTRY_HAS_EXT(DE) \ + ((DE)->ext && MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(DE), \ + MAGIC_STATE_EXT)) +#define MAGIC_DSENTRY_TO_SENTRY(DE) (&((DE)->sentry)) +#define MAGIC_DSENTRY_FROM_SENTRY(E) \ + ((struct _magic_dsentry*)(((char*)(E)) - \ + offsetof(struct _magic_dsentry, sentry))) +#define MAGIC_DSENTRY_TO_TYPE_ARR(DE) ((DE)->type_array) +#define MAGIC_DSENTRY_NEXT_MEMPOOL(DE) ((DE)->next_mpool) +#define MAGIC_DSENTRY_NEXT_MEMBLOCK(DE) ((DE)->next_mblock) +#define MAGIC_DSENTRY_HAS_NEXT_MEMPOOL(DE) ((DE)->next_mpool != NULL) +#define MAGIC_DSENTRY_HAS_NEXT_MEMBLOCK(DE) ((DE)->next_mblock != NULL) + +#define MAGIC_DSENTRY_MSTATE_ALIVE (~(0xFEE1DEAD)) +#define MAGIC_DSENTRY_MSTATE_DEAD 0xFEE1DEAD +#define MAGIC_DSENTRY_MSTATE_FREED 0xDEADBEEF +#define MAGIC_DSENTRY_MNUM MAGIC_DSENTRY_MSTATE_ALIVE +#define MAGIC_DSENTRY_MNUM_NULL 0 +#define MAGIC_DSENTRY_SITE_ID_NULL 0 + +#define MAGIC_DSENTRY_MNUM_OK(D) ((D)->magic_number == MAGIC_DSENTRY_MNUM) +#define MAGIC_DSENTRY_MSTATE_OK(D) \ + ((D)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE \ + || (D)->magic_state == MAGIC_DSENTRY_MSTATE_DEAD \ + || (D)->magic_state == MAGIC_DSENTRY_MSTATE_FREED) +#define MAGIC_DSENTRY_MSTATE_C(D) \ + ((D)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE ? 'A' \ + : (D)->magic_state == MAGIC_DSENTRY_MSTATE_DEAD ? 'D' \ + : (D)->magic_state == MAGIC_DSENTRY_MSTATE_FREED ? 'F' : '?') + +#define MAGIC_DSENTRY_PRINT(DE, EXPAND_TYPE_STR) do { \ + _magic_printf("DSENTRY: (~mnum=%08x, mstate=%c, address=0x%08x, " \ + "site_id=" MAGIC_ID_FORMAT ", next=0x%08x, sentry=", \ + ~((DE)->magic_number), MAGIC_DSENTRY_MSTATE_C(DE), (unsigned) (DE),\ + (DE)->site_id, (unsigned) (DE)->next); \ + MAGIC_SENTRY_PRINT(MAGIC_DSENTRY_TO_SENTRY(DE), EXPAND_TYPE_STR); \ + _magic_printf(")"); \ + } while(0) + +/* Iterate through all the top-level dsentries. */ +#define MAGIC_DSENTRY_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) do { \ + if(HEAD) { \ + DSENTRY=NULL; \ + while(!DSENTRY || MAGIC_DSENTRY_HAS_NEXT(DSENTRY)) { \ + PREV_DSENTRY = DSENTRY; \ + DSENTRY = !DSENTRY ? HEAD : MAGIC_DSENTRY_NEXT(DSENTRY); \ + assert(magic_check_dsentry(DSENTRY, 0) \ + && "Bad magic dsentry looked up!"); \ + SENTRY = MAGIC_DSENTRY_TO_SENTRY(DSENTRY); \ + DO \ + } \ + } \ + } while(0) + +#define MAGIC_DSENTRY_ALIVE_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) do { \ + MAGIC_DSENTRY_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY, \ + if((DSENTRY)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE) { \ + DO \ + } \ + ); \ + } while(0) + +/* Iterate through all the top-level dsentries and nest at the block level. */ +#define MAGIC_DSENTRY_NESTED_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) do { \ + MAGIC_DSENTRY_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY, \ + DO \ + if(magic_lookup_nested_dsentries \ + && MAGIC_STATE_FLAG(SENTRY, MAGIC_STATE_MEMPOOL)) { \ + struct _magic_dsentry *MEMPOOL_DSENTRY = DSENTRY; \ + MAGIC_DSENTRY_MEMBLOCK_ITER(MEMPOOL_DSENTRY, DSENTRY, SENTRY, \ + DO \ + ); \ + DSENTRY = MEMPOOL_DSENTRY; \ + } \ + ); \ + } while(0) + +#define MAGIC_DSENTRY_ALIVE_NESTED_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) \ + do { \ + MAGIC_DSENTRY_NESTED_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY, \ + if((DSENTRY)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE) { \ + DO \ + } \ + ); \ + } while(0) + +/* Iterate through all the block-level dsentries. */ +#define MAGIC_DSENTRY_BLOCK_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) do { \ + MAGIC_DSENTRY_NESTED_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY, \ + if(!MAGIC_STATE_FLAG(SENTRY, MAGIC_STATE_MEMPOOL)) { \ + DO \ + } \ + ); \ + } while(0) + +#define MAGIC_DSENTRY_ALIVE_BLOCK_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) \ + do { \ + MAGIC_DSENTRY_BLOCK_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY, \ + if((DSENTRY)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE) { \ + DO \ + } \ + ); \ + } while(0) + +#define MAGIC_DSENTRY_MEMPOOL_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) do { \ + if(HEAD) { \ + DSENTRY=NULL; \ + while(!DSENTRY || MAGIC_DSENTRY_HAS_NEXT_MEMPOOL(DSENTRY)) { \ + PREV_DSENTRY = DSENTRY; \ + DSENTRY = !DSENTRY ? HEAD \ + : MAGIC_DSENTRY_NEXT_MEMPOOL(DSENTRY); \ + assert(magic_check_dsentry(DSENTRY, 0) \ + && "Bad magic dsentry looked up!"); \ + SENTRY = MAGIC_DSENTRY_TO_SENTRY(DSENTRY); \ + DO \ + } \ + } \ + } while(0) + +#define MAGIC_DSENTRY_MEMPOOL_ALIVE_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY,DO) \ + do { \ + MAGIC_DSENTRY_MEMPOOL_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY, \ + if((DSENTRY)->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE) { \ + DO \ + } \ + ); \ + } while(0) + +#define MAGIC_DSENTRY_MEMBLOCK_ITER(MEMPOOL_DSENTRY, \ + MEMBLOCK_DSENTRY,MEMBLOCK_SENTRY,DO) \ + do { \ + if(MEMPOOL_DSENTRY) { \ + assert(magic_check_dsentry(MEMPOOL_DSENTRY, 0) \ + && "Bad magic dsentry looked up!"); \ + assert(MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(MEMPOOL_DSENTRY), \ + MAGIC_STATE_MEMPOOL) && "Bad mempool dsentry looked up!"); \ + MEMBLOCK_DSENTRY = MAGIC_DSENTRY_NEXT_MEMBLOCK(MEMPOOL_DSENTRY); \ + while (MEMBLOCK_DSENTRY && (MEMBLOCK_DSENTRY != MEMPOOL_DSENTRY)) {\ + assert(magic_check_dsentry(MEMBLOCK_DSENTRY, 0) \ + && "Bad magic dsentry looked up!"); \ + MEMBLOCK_SENTRY = MAGIC_DSENTRY_TO_SENTRY(MEMBLOCK_DSENTRY); \ + assert(MAGIC_STATE_FLAG(MEMBLOCK_SENTRY, MAGIC_STATE_MEMBLOCK) \ + && "Bad memblock dsentry looked up!"); \ + DO \ + MEMBLOCK_DSENTRY=MAGIC_DSENTRY_NEXT_MEMBLOCK(MEMBLOCK_DSENTRY);\ + } \ + } \ + } while(0) + +#define MAGIC_DSENTRY_MEMPOOL_LOOKUP(MEMBLOCK_DSENTRY,MEMPOOL_DSENTRY) do { \ + if (MEMBLOCK_DSENTRY) { \ + struct _magic_dsentry *DSENTRY; \ + struct _magic_sentry *SENTRY; \ + DSENTRY = MEMBLOCK_DSENTRY; \ + do { \ + assert(magic_check_dsentry(DSENTRY, 0) \ + && "Bad magic dsentry looked up!"); \ + SENTRY = MAGIC_DSENTRY_TO_SENTRY(DSENTRY); \ + if (MAGIC_STATE_FLAG(SENTRY, MAGIC_STATE_MEMPOOL)) { \ + MEMPOOL_DSENTRY = DSENTRY; \ + break; \ + } \ + DSENTRY = MAGIC_DSENTRY_NEXT_MEMBLOCK(DSENTRY); \ + } while (DSENTRY != MEMBLOCK_DSENTRY); \ + } \ + } while(0) + +#define MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(HEAD, PREV_DSENTRY, DSENTRY, SENTRY, \ + PN, N, ID, DO) do { \ + MAGIC_DSENTRY_ALIVE_ITER(HEAD,PREV_DSENTRY,DSENTRY,SENTRY, \ + if((!(PN) || !strcmp((DSENTRY)->parent_name, (PN))) \ + && (!(N) || !strcmp((SENTRY)->name, (N))) \ + && (!(ID) || ((ID) == (DSENTRY)->site_id))) { \ + DO \ + } \ + ); \ + } while(0) + +#define MAGIC_DSENTRY_NUM(HEAD,NUM) do { \ + struct _magic_dsentry *_prev_dsentry, *_dsentry; \ + struct _magic_sentry *_sentry; \ + *(NUM) = 0; \ + MAGIC_DSENTRY_ITER(HEAD,_prev_dsentry,_dsentry,_sentry,(*(NUM))++;); \ + } while(0) + +#define MAGIC_DSENTRY_ALIVE_NUM(HEAD,NUM) do { \ + struct _magic_dsentry *_prev_dsentry, *_dsentry; \ + struct _magic_sentry *_sentry; \ + *(NUM) = 0; \ + MAGIC_DSENTRY_ALIVE_ITER(HEAD,_prev_dsentry,_dsentry,_sentry,(*(NUM))++;); \ + } while(0) + +#define MAGIC_DSENTRY_BLOCK_NUM(HEAD,NUM) do { \ + struct _magic_dsentry *_prev_dsentry, *_dsentry; \ + struct _magic_sentry *_sentry; \ + *(NUM) = 0; \ + MAGIC_DSENTRY_BLOCK_ITER(HEAD,_prev_dsentry,_dsentry,_sentry,(*(NUM))++;); \ + } while(0) + +#define MAGIC_DSENTRY_ALIVE_BLOCK_NUM(HEAD,NUM) do { \ + struct _magic_dsentry *_prev_dsentry, *_dsentry; \ + struct _magic_sentry *_sentry; \ + *(NUM) = 0; \ + MAGIC_DSENTRY_ALIVE_BLOCK_ITER(HEAD,_prev_dsentry,_dsentry,_sentry,(*(NUM))++;); \ + } while(0) + +#define MAGIC_DEAD_DSENTRIES_NEED_FREEING() \ + (magic_num_dead_dsentries > MAGIC_MAX_DEAD_DSENTRIES \ + || magic_size_dead_dsentries > MAGIC_MAX_DEAD_DSENTRIES_SIZE) + +#define MAGIC_SENTRY_OVERLAPS(S, START, END) \ + ((char*)(S)->address<=(char*)(END) \ + && (char*)(S)->address+(S)->type->size-1>=(char*)(START)) + +#define MAGIC_SENTRY_RANGE_ALIVE_BLOCK_ITER(SENTRY,START,END,DO) do { \ + int __i; \ + struct _magic_dsentry *__prev_dsentry, *__dsentry; \ + if (magic_sentry_rl_index) { \ + char *__addr = NULL; \ + SENTRY = NULL; \ + while (1) { \ + __addr = __addr ? SENTRY->address : ((char*)END) + 1; \ + SENTRY = magic_sentry_rl_pred_lookup(__addr); \ + if (!SENTRY || !MAGIC_SENTRY_OVERLAPS(SENTRY, START, ((char*)-1))) break; \ + DO \ + } \ + break; \ + } \ + for (__i=0;__i<_magic_sentries_num;__i++) { \ + SENTRY = &_magic_sentries[__i]; \ + if (MAGIC_SENTRY_OVERLAPS(SENTRY, START, END)) { DO } \ + } \ + MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, __prev_dsentry, __dsentry, SENTRY, \ + if (MAGIC_SENTRY_OVERLAPS(SENTRY, START, END)) { \ + if(magic_lookup_nested_dsentries \ + && MAGIC_STATE_FLAG(SENTRY, MAGIC_STATE_MEMPOOL)) { \ + struct _magic_dsentry *MEMPOOL_DSENTRY = __dsentry; \ + struct _magic_dsentry *__dsentry2; \ + MAGIC_DSENTRY_MEMBLOCK_ITER(MEMPOOL_DSENTRY, __dsentry2, SENTRY, \ + if (MAGIC_SENTRY_OVERLAPS(SENTRY, START, END)) { DO } \ + ); \ + } \ + else { DO } \ + } \ + ); \ + } while(0) + +/* Magic out-of-band dynamic state entry macros. */ +#define MAGIC_OBDSENTRY_TO_DSENTRY(OBDE) (&((OBDE)->dsentry)) +#define MAGIC_OBDSENTRY_FROM_DSENTRY(DE) \ + ((struct _magic_obdsentry*)(((char*)(DE)) - \ + offsetof(struct _magic_obdsentry, dsentry))) +#define MAGIC_OBDSENTRY_TO_SENTRY(OBDE) \ + MAGIC_DSENTRY_TO_SENTRY(MAGIC_OBDSENTRY_TO_DSENTRY(OBDE)) +#define MAGIC_OBDSENTRY_FROM_SENTRY(E) \ + MAGIC_OBDSENTRY_FROM_DSENTRY(MAGIC_DSENTRY_FROM_SENTRY(E)) +#define MAGIC_OBDSENTRY_IS_FREE(OBDE) \ + ((OBDE)->dsentry.sentry.flags == 0) +#define MAGIC_OBDSENTRY_FREE(OBDE) ((OBDE)->dsentry.sentry.flags = 0) + +/* Magic memory pool state entry macros. */ +#define MAGIC_MPDESC_IS_FREE(POOL) ((POOL)->is_alive == 0) +#define MAGIC_MPDESC_ALLOC(POOL) ((POOL)->is_alive = 1) +#if MAGIC_MEM_USAGE_OUTPUT_CTL +#define MAGIC_MPDESC_FREE(POOL) do { \ + (POOL)->is_alive = 0; \ + (POOL)->addr = NULL; \ + (POOL)->dtype_id = 0; \ +} while (0) +#else +#define MAGIC_MPDESC_FREE(POOL) do { \ + (POOL)->is_alive = 0; \ + (POOL)->addr = NULL; \ +} while (0) +#endif + +#define MAGIC_SELEMENT_MAX_PTR_RECURSIONS 100 + +#define MAGIC_SELEMENT_NAME_PRINT(E) do { \ + if((E)->sentry) { \ + magic_type_walk_root((E)->sentry->type, 0, \ + (unsigned long) ((char*)(E)->address - \ + (char*)(E)->sentry->address), magic_selement_name_print_cb, \ + (void*)(E)); \ + } \ + else { \ + _magic_printf("???"); \ + } \ + } while(0) +#define MAGIC_CHECK_TRG(T) \ + (magic_type_target_walk(T, NULL, NULL, magic_type_count_cb, NULL) >= 0) +#define MAGIC_SELEMENT_HAS_TRG(E) \ + ((E)->type->size == sizeof(void*) \ + && MAGIC_CHECK_TRG(*((void**)(E)->address))) +#define MAGIC_SELEMENT_PRINT(E, FLAGS) do { \ + _magic_printf("SELEMENT: (parent=%s, num=%d, depth=%d, address=0x%08x,"\ + " name=", (E)->sentry ? (E)->sentry->name : "???", (E)->num, \ + (E)->depth, (E)->address); \ + MAGIC_SELEMENT_NAME_PRINT(E); \ + _magic_printf(", type="); \ + if ((E)->type) MAGIC_TYPE_PRINT((E)->type, FLAGS); \ + if(((FLAGS) & MAGIC_EXPAND_SENTRY) && (E)->sentry) { \ + _magic_printf(", sentry="); \ + MAGIC_SENTRY_PRINT((E)->sentry, FLAGS); \ + } \ + _magic_printf(")"); \ + } while(0) + +/* Magic external library descriptor macros. */ +#define MAGIC_LIBDESC_PRINT(LD) \ + _magic_printf("LIBDESC: (name=%s, text_range=[%p,%p], data_range=[%p,%p], "\ + "alloc_address=%p, alloc_size=%zu)", (LD)->name, (LD)->text_range[0], \ + (LD)->text_range[1], (LD)->data_range[0], (LD)->data_range[1], \ + (LD)->alloc_address, (LD)->alloc_size); + +/* Magic SO library descriptor macros. */ +#define MAGIC_SODESC_PREV(SD) ((SD)->prev) +#define MAGIC_SODESC_HAS_PREV(SD) ((SD)->prev != NULL) +#define MAGIC_SODESC_NEXT(SD) ((SD)->next) +#define MAGIC_SODESC_HAS_NEXT(SD) ((SD)->next != NULL) + +#define MAGIC_SODESC_PRINT(SD) do { \ + _magic_printf("SODESC: (address=%p, prev=%p, next=%p, ", (SD), \ + (SD)->prev, (SD)->next); \ + MAGIC_LIBDESC_PRINT(&((SD)->lib)); \ + _magic_printf(")"); \ + } while(0) + +#define MAGIC_SODESC_ITER(HEAD, SODESC, DO) do { \ + if (HEAD) { \ + SODESC = NULL; \ + while(!SODESC || MAGIC_SODESC_HAS_NEXT(SODESC)) { \ + SODESC = !SODESC ? HEAD : MAGIC_SODESC_NEXT(SODESC); \ + DO \ + } \ + } \ + } while(0) + +#define MAGIC_SODESC_ITER_SAFE(HEAD, SODESC, DO) do { \ + struct _magic_sodesc *sodesc_next; \ + if (HEAD) { \ + SODESC = NULL; \ + while(!SODESC || sodesc_next != NULL) { \ + SODESC = !SODESC ? HEAD : sodesc_next; \ + sodesc_next = MAGIC_SODESC_NEXT(SODESC); \ + DO \ + } \ + } \ + } while(0) + +/* Magic DSO library descriptor macros. */ +#define MAGIC_DSODESC_PREV(DD) ((DD)->prev) +#define MAGIC_DSODESC_HAS_PREV(DD) ((DD)->prev != NULL) +#define MAGIC_DSODESC_NEXT(DD) ((DD)->next) +#define MAGIC_DSODESC_HAS_NEXT(DD) ((DD)->next != NULL) + +#define MAGIC_DSODESC_PRINT(DD) do { \ + _magic_printf("DSODESC: (address=%p, prev=%p, next=%p, handle=%p, " \ + "ref_count=%d, ", (DD), (DD)->prev, (DD)->next, (DD)->handle, \ + (DD)->ref_count); \ + MAGIC_LIBDESC_PRINT(&((DD)->lib)); \ + _magic_printf(")"); \ + } while(0) + +#define MAGIC_DSODESC_ITER(HEAD, DSODESC, DO) do { \ + if (HEAD) { \ + DSODESC = NULL; \ + while(!DSODESC || MAGIC_DSODESC_HAS_NEXT(DSODESC)) { \ + DSODESC = !DSODESC ? HEAD : MAGIC_DSODESC_NEXT(DSODESC); \ + DO \ + } \ + } \ + } while(0) + +#define MAGIC_DSODESC_ITER_SAFE(HEAD, DSODESC, DO) do { \ + struct _magic_dsodesc *dsodesc_next; \ + if (HEAD) { \ + DSODESC = NULL; \ + while(!DSODESC || dsodesc_next != NULL) { \ + DSODESC = !DSODESC ? HEAD : dsodesc_next; \ + dsodesc_next = MAGIC_DSODESC_NEXT(DSODESC); \ + DO \ + } \ + } \ + } while(0) + +/* Magic value casts. */ +#define MAGIC_VALUE_CAST_DEBUG MAGIC_DEBUG_SET(0) + +#define MAGIC_CHECKED_VALUE_SRC_CAST(SV, ST, DV, DT, RP, CS) \ + do { \ + ST value = SV; \ + DV = (DT) value; \ + if (((ST) (DV)) != value) { \ + *(RP) = MAGIC_ERANGE; \ + } \ + else if(CS && value && (((DV) <= (DT) 0 && value >= (ST) 0) || \ + ((DV) >= (DT) 0 && value <= (ST) 0))) { \ + *(RP) = MAGIC_ESIGN; \ + } \ + if(MAGIC_VALUE_CAST_DEBUG) { \ + _magic_printf("SRC "); \ + MAGIC_SELEMENT_PRINT(src_selement, MAGIC_EXPAND_TYPE_STR); \ + _magic_printf("\n"); \ + _magic_printf("DST "); \ + MAGIC_SELEMENT_PRINT(dst_selement, MAGIC_EXPAND_TYPE_STR); \ + _magic_printf("\n"); \ + _magic_printf("MAGIC_CHECKED_VALUE_SRC_CAST: " \ + "types=%s-->%s, value=", #ST, #DT); \ + magic_selement_print_value(src_selement); \ + _magic_printf("-->(long/unsigned long/void*)%d/%u/%08x, " \ + "ERANGE=%d, ESIGN=%d\n", (long) (DV), (unsigned long) (DV), \ + (unsigned long) (DV), *(RP) == MAGIC_ERANGE, \ + *(RP) == MAGIC_ESIGN); \ + } \ + } while(0) + +#define MAGIC_CHECKED_VALUE_DST_CAST(SV, ST, DV, DT, RP) \ + do { \ + DT value = (DT) SV; \ + if (((ST) value) != (SV)) { \ + *(RP) = MAGIC_ERANGE; \ + } \ + *((DT*) (DV)) = value; \ + if (MAGIC_VALUE_CAST_DEBUG) { \ + _magic_selement_t tmp_selement = *dst_selement; \ + tmp_selement.address = DV; \ + _magic_printf("MAGIC_CHECKED_VALUE_DST_CAST: types=%s-->%s, " \ + "value=(long/unsigned long/void*)%d/%u/%08x-->", #ST, #DT, \ + (long) (SV), (unsigned long) (SV), (unsigned long) (SV)); \ + magic_selement_print_value(&tmp_selement); \ + _magic_printf(", ERANGE=%d\n", *(RP) == MAGIC_ERANGE); \ + } \ + } while(0) + +/* Magic utility macros. */ +#define MAGIC_ABS(X) ((X) >= 0 ? (X) : -(X)) + +/* Magic page size. */ +#define MAGIC_PAGE_SIZE (magic_sys_pagesize ? magic_sys_pagesize : magic_get_sys_pagesize()) +EXTERN unsigned long magic_sys_pagesize; + +/* Magic sections. */ +#define MAGIC_DATA_SECTION_START ((void*)&__start_magic_data) +#define MAGIC_DATA_SECTION_END ((void*)&__stop_magic_data) +#define MAGIC_DATA_RO_SECTION_START ((void*)&__start_magic_data_ro) +#define MAGIC_DATA_RO_SECTION_END ((void*)&__stop_magic_data_ro) +#define MAGIC_ST_DATA_SECTION_START ((void*)&__start_magic_data_st) +#define MAGIC_ST_DATA_SECTION_END ((void*)&__stop_magic_data_st) +#define MAGIC_ST_DATA_RO_SECTION_START ((void*)&__start_magic_data_st_ro) +#define MAGIC_ST_DATA_RO_SECTION_END ((void*)&__stop_magic_data_st_ro) +#define MAGIC_TEXT_SECTION_START ((void*)&__start_magic_functions) +#define MAGIC_TEXT_SECTION_END ((void*)&__stop_magic_functions) +#define MAGIC_ST_TEXT_SECTION_START ((void*)&__start_magic_functions_st) +#define MAGIC_ST_TEXT_SECTION_END ((void*)&__stop_magic_functions_st) +EXTERN void* __start_magic_data; +EXTERN void* __stop_magic_data; +EXTERN void* __start_magic_data_ro; +EXTERN void* __stop_magic_data_ro; +EXTERN void* __start_magic_data_st; +EXTERN void* __stop_magic_data_st; +EXTERN void* __start_magic_data_st_ro; +EXTERN void* __stop_magic_data_st_ro; +EXTERN void* __start_magic_functions; +EXTERN void* __stop_magic_functions; +EXTERN void* __start_magic_functions_st; +EXTERN void* __stop_magic_functions_st; + +#if MAGIC_THREAD_SAFE +#if MAGIC_FORCE_LOCKS +#define MAGIC_DSENTRY_LOCK() magic_dsentry_lock(magic_dsentry_lock_args) +#define MAGIC_DSENTRY_UNLOCK() magic_dsentry_unlock(magic_dsentry_unlock_args) +#define MAGIC_DFUNCTION_LOCK() magic_dfunction_lock(magic_dfunction_lock_args) +#define MAGIC_DFUNCTION_UNLOCK() \ + magic_dfunction_unlock(magic_dfunction_unlock_args) +#define MAGIC_DSODESC_LOCK() magic_dsodesc_lock(magic_dsodesc_lock_args) +#define MAGIC_DSODESC_UNLOCK() magic_dsodesc_unlock(magic_dsodesc_unlock_args) +#define MAGIC_MPDESC_LOCK() magic_mpdesc_lock(magic_mpdesc_lock_args) +#define MAGIC_MPDESC_UNLOCK() magic_mpdesc_unlock(magic_mpdesc_unlock_args) +#else +#define MAGIC_GENERIC_LOCK(LOCK,ARGS) \ + do { \ + int l; \ + if (LOCK) { \ + l = LOCK(ARGS); \ + assert(l == 0 && "bad lock"); \ + } \ + } while (0) + +#define MAGIC_DSENTRY_LOCK() \ + MAGIC_GENERIC_LOCK(magic_dsentry_lock,magic_dsentry_lock_args) +#define MAGIC_DSENTRY_UNLOCK() \ + MAGIC_GENERIC_LOCK(magic_dsentry_unlock,magic_dsentry_unlock_args) +#define MAGIC_DFUNCTION_LOCK() \ + MAGIC_GENERIC_LOCK(magic_dfunction_lock,magic_dfunction_lock_args) +#define MAGIC_DFUNCTION_UNLOCK() \ + MAGIC_GENERIC_LOCK(magic_dfunction_unlock,magic_dfunction_unlock_args) +#define MAGIC_DSODESC_LOCK() \ + MAGIC_GENERIC_LOCK(magic_dsodesc_lock,magic_dsodesc_lock_args) +#define MAGIC_DSODESC_UNLOCK() \ + MAGIC_GENERIC_LOCK(magic_dsodesc_unlock,magic_dsodesc_unlock_args) +#define MAGIC_MPDESC_LOCK() \ + MAGIC_GENERIC_LOCK(magic_mpdesc_lock,magic_mpdesc_lock_args) +#define MAGIC_MPDESC_UNLOCK() \ + MAGIC_GENERIC_LOCK(magic_mpdesc_unlock,magic_mpdesc_unlock_args) +#endif +#define MAGIC_MULTIPLE_LOCK(DS, DF, DSO, MP) \ + do { \ + if (DS) \ + MAGIC_DSENTRY_LOCK(); \ + if (DF) \ + MAGIC_DFUNCTION_LOCK(); \ + if (DSO) \ + MAGIC_DSODESC_LOCK(); \ + if (MP) \ + MAGIC_MPDESC_LOCK(); \ + } while (0) +#define MAGIC_MULTIPLE_UNLOCK(DS, DF, DSO, MP) \ + do { \ + if (MP) \ + MAGIC_MPDESC_UNLOCK(); \ + if (DSO) \ + MAGIC_DSODESC_UNLOCK(); \ + if (DF) \ + MAGIC_DFUNCTION_UNLOCK(); \ + if (DS) \ + MAGIC_DSENTRY_UNLOCK(); \ + } while (0) +#define MAGIC_MULTIPLE_LOCK_BLOCK(DS, DF, DSO, MP, BLOCK) \ + do { \ + MAGIC_MULTIPLE_LOCK(DS, DF, DSO, MP); \ + BLOCK \ + MAGIC_MULTIPLE_UNLOCK(DS, DF, DSO, MP); \ + } while (0) +#else +#define MAGIC_DSENTRY_LOCK() +#define MAGIC_DSENTRY_UNLOCK() +#define MAGIC_DFUNCTION_LOCK() +#define MAGIC_DFUNCTION_UNLOCK() +#define MAGIC_DSODESC_LOCK() +#define MAGIC_DSODESC_UNLOCK() +#define MAGIC_MPDESC_LOCK() +#define MAGIC_MPDESC_UNLOCK() +#define MAGIC_MULTIPLE_LOCK(DS, DF, DSO, MP) +#define MAGIC_MULTIPLE_UNLOCK(DS, DF, DSO, MP) +#define MAGIC_MULTIPLE_LOCK_BLOCK(DS, DF, DSO, MP, BLOCK) \ + do { \ + BLOCK \ + } while (0) +#endif + +/* Debug. */ +#define MAGIC_DEBUG_HIGH 3 +#define MAGIC_DEBUG_AVG 2 +#define MAGIC_DEBUG_LOW 1 +#define MAGIC_DEBUG_NONE 0 +#define MAGIC_DEBUG \ + MAGIC_DEBUG_SELECT(MAGIC_DEBUG_HIGH, MAGIC_DEBUG_NONE) + +#if MAGIC_DEBUG +#define MAGIC_DEBUG_CODE(L, X) \ + do { \ + if(L > MAGIC_DEBUG) break; \ + X \ + } while(0) +#else +#define MAGIC_DEBUG_CODE(L, X) +#endif + +/* Magic Address Space Randomization (ASRPass) */ +#define _magic_asr_seed (_magic_vars->asr_seed) +#define _magic_asr_heap_map_do_permutate ( \ + _magic_vars->asr_heap_map_do_permutate) +#define _magic_asr_heap_max_offset (_magic_vars->asr_heap_max_offset) +#define _magic_asr_heap_max_padding (_magic_vars->asr_heap_max_padding) +#define _magic_asr_map_max_offset_pages (_magic_vars->asr_map_max_offset_pages) +#define _magic_asr_map_max_padding_pages ( \ + _magic_vars->asr_map_max_padding_pages) + +/* Magic type array. */ +#define _magic_types (_magic_vars->types) +#define _magic_types_num (_magic_vars->types_num) +#define _magic_types_next_id (_magic_vars->types_next_id) + +/* Magic function array. */ +#define _magic_functions (_magic_vars->functions) +#define _magic_functions_num (_magic_vars->functions_num) +#define _magic_functions_next_id (_magic_vars->functions_next_id) + +/* Magic dynamic function list. */ +#define _magic_first_dfunction (_magic_vars->first_dfunction) +#define _magic_last_dfunction (_magic_vars->last_dfunction) +#define _magic_dfunctions_num (_magic_vars->dfunctions_num) + +/* Magic functions hash vars. */ +#define magic_function_hash_buff (_magic_vars->function_hash_buff) +#define magic_function_hash_buff_offset (_magic_vars->function_hash_buff_offset) +#define magic_function_hash_buff_size (_magic_vars->function_hash_buff_size) +#define magic_function_hash_head (_magic_vars->function_hash_head) + +/* Magic dynamic state index array. */ +#define _magic_dsindexes (_magic_vars->dsindexes) +#define _magic_dsindexes_num (_magic_vars->dsindexes_num) + +/* Magic dynamic state entry list. */ +#define _magic_first_dsentry (_magic_vars->first_dsentry) +#define magic_num_dead_dsentries (_magic_vars->num_dead_dsentries) +#define magic_size_dead_dsentries (_magic_vars->size_dead_dsentries) + +/* Magic memory pool dynamic state entry list. */ +#define _magic_first_mempool_dsentry (_magic_vars->first_mempool_dsentry) + +/* Magic SO library descriptor list. */ +#define _magic_first_sodesc (_magic_vars->first_sodesc) +#define _magic_last_sodesc (_magic_vars->last_sodesc) +#define _magic_sodescs_num (_magic_vars->sodescs_num) + +/* Magic DSO library descriptor list. */ +#define _magic_first_dsodesc (_magic_vars->first_dsodesc) +#define _magic_last_dsodesc (_magic_vars->last_dsodesc) +#define _magic_dsodescs_num (_magic_vars->dsodescs_num) + +/* Magic stack-related variables. */ +#define _magic_first_stack_dsentry (_magic_vars->first_stack_dsentry) +#define _magic_last_stack_dsentry (_magic_vars->last_stack_dsentry) + +/* Magic default stubs. */ +EXTERN struct _magic_type magic_default_type; +EXTERN struct _magic_dsentry magic_default_dsentry; +EXTERN struct _magic_dfunction magic_default_dfunction; +EXTERN struct _magic_type magic_default_ret_addr_type; + +/* Magic vars references. */ +EXTERN struct _magic_vars_t _magic_vars_buff; +EXTERN struct _magic_vars_t *_magic_vars; + +FUNCTION_BLOCK( + +/* Magic vars wrappers. */ +PUBLIC void *_magic_vars_addr(); +PUBLIC size_t _magic_vars_size(); + +/* Magic printf. */ +PUBLIC int magic_null_printf(const char* format, ...); +PUBLIC int magic_err_printf(const char* format, ...); +PUBLIC void magic_set_printf(printf_ptr_t func_ptr); +PUBLIC printf_ptr_t magic_get_printf(void); +PUBLIC void magic_assert_failed(const char *assertion, const char *file, + const char *function, const int line); + +/* Magic utility functions. */ +PUBLIC unsigned long magic_get_sys_pagesize(); + +/* Magic lock primitives. */ +typedef int (*magic_lock_t)(void*); +typedef int (*magic_unlock_t)(void*); + +EXTERN magic_lock_t magic_dsentry_lock; +EXTERN magic_unlock_t magic_dsentry_unlock; +EXTERN void *magic_dsentry_lock_args; +EXTERN void *magic_dsentry_unlock_args; + +EXTERN magic_lock_t magic_dfunction_lock; +EXTERN magic_unlock_t magic_dfunction_unlock; +EXTERN void *magic_dfunction_lock_args; +EXTERN void *magic_dfunction_unlock_args; + +EXTERN magic_lock_t magic_dsodesc_lock; +EXTERN magic_unlock_t magic_dsodesc_unlock; +EXTERN void *magic_dsodesc_lock_args; +EXTERN void *magic_dsodesc_unlock_args; + +EXTERN magic_lock_t magic_mpdesc_lock; +EXTERN magic_unlock_t magic_mpdesc_unlock; +EXTERN void *magic_mpdesc_lock_args; +EXTERN void *magic_mpdesc_unlock_args; + +PUBLIC void magic_dsentry_set_lock_primitives(magic_lock_t lock, + magic_unlock_t unlock, void *lock_args, void *unlock_args); +PUBLIC void magic_dfunction_set_lock_primitives(magic_lock_t lock, + magic_unlock_t unlock, void *lock_args, void *unlock_args); +PUBLIC void magic_dsodesc_set_lock_primitives(magic_lock_t lock, + magic_unlock_t unlock, void *lock_args, void *unlock_args); +PUBLIC void magic_mpdesc_set_lock_primitives(magic_lock_t lock, + magic_unlock_t unlock, void *lock_args, void *unlock_args); + +/* + * Magic void ptr and array (force at the least 1 void* and 1 void array in the + * list of globals). + */ +EXTERN void* MAGIC_VOID_PTR; +EXTERN char MAGIC_VOID_ARRAY[1]; + +/* Magic special types. */ +EXTERN struct _magic_type *MAGIC_VOID_PTR_TYPE; +EXTERN struct _magic_type *MAGIC_VOID_PTR_INT_CAST_TYPE; +EXTERN struct _magic_type *MAGIC_VOID_ARRAY_TYPE; +EXTERN struct _magic_type *MAGIC_PTRINT_TYPE; +EXTERN struct _magic_type *MAGIC_PTRINT_ARRAY_TYPE; + +/* Magic annotations. */ +EXTERN VOLATILE int MAGIC_CALL_ANNOTATION_VAR; + +/* Magic status variables. */ +EXTERN int magic_init_done; +EXTERN int magic_libcommon_active; +EXTERN int magic_lookup_nested_dsentries; +EXTERN int magic_allow_dead_dsentries; +EXTERN int magic_ignore_dead_dsentries; +EXTERN int magic_mmap_dsentry_header_prot; +EXTERN int _magic_enabled; +EXTERN int _magic_checkpoint_enabled; +EXTERN int _magic_lazy_checkpoint_enabled; + +/* Magic page size. */ +EXTERN unsigned long magic_sys_pagesize; + +/* Initialization functions. */ +PUBLIC void magic_init(void); +PUBLIC void magic_stack_init(); + +/* Dfunction functions. */ +PUBLIC int magic_check_dfunction(struct _magic_dfunction *ptr, int flags); +PUBLIC int magic_check_dfunctions(); +PUBLIC int magic_check_dfunctions_safe(); +PUBLIC void magic_print_dfunction(struct _magic_dfunction *dfunction); +PUBLIC void magic_print_dfunctions(); +PUBLIC void magic_print_dfunctions_safe(); +PUBLIC void magic_copy_dfunction(struct _magic_dfunction *dfunction, + struct _magic_dfunction *dst_dfunction); + +/* Dsindex functions. */ +PUBLIC void magic_print_dsindex(struct _magic_dsindex *dsindex); +PUBLIC void magic_print_dsindexes(); + +/* Dsentry functions. */ +PUBLIC int magic_check_dsentry(struct _magic_dsentry *ptr, int flags); +PUBLIC int magic_check_dsentries(); +PUBLIC int magic_check_dsentries_safe(); +PUBLIC void magic_print_dsentry(struct _magic_dsentry *dsentry); +PUBLIC void magic_print_dsentries(); +PUBLIC void magic_print_dsentries_safe(); +PUBLIC void magic_copy_dsentry(struct _magic_dsentry *dsentry, + struct _magic_dsentry *dst_dsentry); + +/* Sodesc functions. */ +PUBLIC void magic_print_sodesc(struct _magic_sodesc *sodesc); +PUBLIC void magic_print_sodescs(); + +/* Dsodesc functions. */ +PUBLIC void magic_print_dsodesc(struct _magic_dsodesc *dsodesc); +PUBLIC void magic_print_dsodescs(); +PUBLIC void magic_print_dsodescs_safe(); + +/* Section functions. */ +PUBLIC void magic_print_sections(); + +/* Lookup functions. */ +PUBLIC struct _magic_sentry* magic_mempool_sentry_lookup_by_range(void *addr, + struct _magic_dsentry *dsentry_buff); +PUBLIC struct _magic_dsindex* magic_dsindex_lookup_by_name(char *parent_name, + char *name); +PUBLIC struct _magic_dsentry* + magic_dsentry_prev_lookup(struct _magic_dsentry* dsentry); +PUBLIC struct _magic_dsentry* + magic_mempool_dsentry_prev_lookup(struct _magic_dsentry* dsentry); +PUBLIC struct _magic_function* magic_function_lookup_by_id(_magic_id_t id, + struct _magic_dfunction *dfunction_buff); +PUBLIC struct _magic_function* magic_function_lookup_by_addr(void *addr, + struct _magic_dfunction *dfunction_buff); +PUBLIC struct _magic_function* magic_function_lookup_by_name(char *parent_name, + char *name); +PUBLIC struct _magic_type* magic_type_lookup_by_name(char *name); +PUBLIC struct _magic_dsodesc* magic_dsodesc_lookup_by_handle(void *handle); +PUBLIC int magic_selement_lookup_by_name(char* name, + _magic_selement_t *selement, struct _magic_dsentry *dsentry_buff); + +/* Magic state function functions. */ +PUBLIC void magic_print_function(struct _magic_function *function); +PUBLIC void magic_print_functions(); + +/* Magic state function lookup hash functions. */ +PUBLIC void magic_function_hash_build(void *buff, size_t buff_size); +PUBLIC void magic_function_hash_destroy(void); +PUBLIC size_t magic_function_hash_estimate_buff_size(int functions_num); +PUBLIC struct _magic_function *magic_function_lookup_by_addr_hash(void *addr, + struct _magic_dfunction *dfunction_buff); +PUBLIC void *magic_function_hash_alloc(size_t size); +PUBLIC void magic_function_hash_dealloc(void *object, size_t size); + +/* Magic state type functions. */ +PUBLIC void magic_print_type(const struct _magic_type* type); +PUBLIC void magic_print_types(); +PUBLIC void magic_type_str_set_print_style(const int style); +PUBLIC int magic_type_str_get_print_style(); +PUBLIC void magic_type_str_print(const struct _magic_type* type); +PUBLIC void magic_type_values_print(const struct _magic_type* type); +PUBLIC void magic_type_names_print(const struct _magic_type* type); +PUBLIC void magic_type_comp_types_print(const struct _magic_type* type, + int flags); +PUBLIC int magic_type_str_print_from_target(void* target); +PUBLIC int magic_type_equals(const struct _magic_type* type, + const struct _magic_type* other_type); +PUBLIC int magic_type_compatible(const struct _magic_type* type, + const struct _magic_type* other_type, int flags); +PUBLIC int magic_type_comp_compatible(const struct _magic_type* type, + const struct _magic_type* other_type); +PUBLIC int magic_type_ptr_is_text(const struct _magic_type* ptr_type); +PUBLIC int magic_type_ptr_is_data(const struct _magic_type* ptr_type); +PUBLIC int magic_type_alloc_needs_varsized_array(const struct _magic_type* type, + size_t alloc_size, int *num_elements); +PUBLIC size_t +magic_type_alloc_get_varsized_array_size(const struct _magic_type* type, + int num_elements); +PUBLIC void magic_type_parse_varsized_array(const struct _magic_type *type, + const struct _magic_type **sub_struct_type, + const struct _magic_type **sub_array_type, + size_t *sub_array_offset, + size_t *sub_array_size); + +/* Magic type walk functions. */ +typedef int (*magic_type_walk_cb_t)(const struct _magic_type*, unsigned, int, + const struct _magic_type*, const unsigned, int, void*); +PUBLIC int magic_type_walk_flags(const struct _magic_type* parent_type, + unsigned parent_offset, int child_num, const struct _magic_type* type, + unsigned offset, const unsigned min_offset, const unsigned max_offset, + const magic_type_walk_cb_t cb, void* cb_args, int flags); +PUBLIC int magic_type_target_walk(void* target, + struct _magic_dsentry** trg_dsentry, + struct _magic_dfunction** trg_dfunction, + const magic_type_walk_cb_t cb, void* cb_args); +PUBLIC int magic_type_walk_as_void_array(const struct _magic_type* parent_type, + unsigned parent_offset, int child_num, const struct _magic_type* type, + unsigned offset, const unsigned min_offset, const unsigned max_offset, + const magic_type_walk_cb_t cb, void* cb_args); +PUBLIC int +magic_type_walk_as_ptrint_array(const struct _magic_type* parent_type, + unsigned parent_offset, int child_num, const struct _magic_type* type, + void* offset_addr, unsigned offset, const unsigned min_offset, + const unsigned max_offset, const magic_type_walk_cb_t cb, void* cb_args); +PUBLIC void magic_type_walk_step(const struct _magic_type *type, + int child_num, const struct _magic_type **child_type, + unsigned *child_offset, int walk_flags); + +/* Magic type walk callbacks. */ +PUBLIC int magic_type_str_print_cb(const struct _magic_type* parent_type, + const unsigned parent_offset, int child_num, const struct _magic_type* type, + const unsigned offset, int depth, void* cb_args); +PUBLIC int magic_selement_name_print_cb(const struct _magic_type* parent_type, + const unsigned parent_offset, int child_num, const struct _magic_type* type, + const unsigned offset, int depth, void* cb_args); +PUBLIC int magic_selement_name_get_cb(const struct _magic_type *parent_type, + const unsigned parent_offset, int child_num, const struct _magic_type *type, + const unsigned offset, int depth, void *args_array); +PUBLIC int magic_type_count_cb(const struct _magic_type* parent_type, + const unsigned parent_offset, int child_num, const struct _magic_type* type, + const unsigned offset, int depth, void* cb_args); +PUBLIC int magic_type_child_offset_cb(const struct _magic_type* parent_type, + const unsigned parent_offset, int child_num, const struct _magic_type* type, + const unsigned offset, int depth, void* cb_args); + +) + +/* Magic type walk helpers. */ +#define magic_type_walk(parent_type, parent_offset, child_num, type, offset, \ + min_offset, max_offset, cb, cb_args) \ + magic_type_walk_flags(parent_type, parent_offset, child_num, type, offset, \ + min_offset, max_offset, cb, cb_args, MAGIC_TYPE_WALK_DEFAULT_FLAGS) +#define magic_type_walk_root(type, min_offset, max_offset, cb, cb_args) \ + magic_type_walk(NULL, 0, 0, type, 0, min_offset, max_offset, cb, cb_args) +#define magic_type_walk_root_at_offset(type, offset, cb, cb_args) \ + magic_type_walk_root(type, offset, offset, cb, cb_args) +#define magic_type_walk_root_all(type, cb, cb_args) \ + magic_type_walk_root(type, 0, ULONG_MAX, cb, cb_args) + +/* Magic size functions. */ +PUBLIC size_t magic_type_get_size(struct _magic_type *type, int flags); +PUBLIC size_t magic_types_get_size(int flags); +PUBLIC size_t magic_function_get_size(struct _magic_function *function, + int flags); +PUBLIC size_t magic_functions_get_size(int flags); +PUBLIC size_t magic_dfunctions_get_size(int flags); +PUBLIC size_t magic_sentry_get_size(struct _magic_sentry *sentry, int flags); +PUBLIC size_t magic_sentries_get_size(int flags); +PUBLIC size_t magic_dsentries_get_size(int flags); +PUBLIC size_t magic_dsindex_get_size(struct _magic_dsindex *dsindex, + int flags); +PUBLIC size_t magic_dsindexes_get_size(int flags); +PUBLIC size_t magic_sodesc_get_size(struct _magic_sodesc *sodesc, + int flags); +PUBLIC size_t magic_sodescs_get_size(int flags); +PUBLIC size_t magic_dsodesc_get_size(struct _magic_dsodesc *dsodesc, + int flags); +PUBLIC size_t magic_dsodescs_get_size(int flags); +PUBLIC size_t magic_metadata_get_size(int flags); +PUBLIC size_t magic_sentries_data_get_size(int flags); +PUBLIC size_t magic_dsentries_data_get_size(int flags); +PUBLIC size_t magic_other_data_get_size(int flags); +PUBLIC size_t magic_data_get_size(int flags); +PUBLIC void magic_print_size_stats(int flags); + +#define MAGIC_SIZE_VALUE_SET 0x0001 +#define MAGIC_SIZE_NAMES 0x0002 +#define MAGIC_SIZE_DSENTRY_NAMES 0x0004 +#define MAGIC_SIZE_DSINDEX_NAMES 0x0008 +#define MAGIC_SIZE_TYPE_NAMES 0x0010 +#define MAGIC_SIZE_MEMBER_NAMES 0x0020 +#define MAGIC_SIZE_COMP_TYPES 0x0040 +#define MAGIC_SIZE_ALL (MAGIC_SIZE_VALUE_SET | MAGIC_SIZE_NAMES | \ + MAGIC_SIZE_DSENTRY_NAMES | MAGIC_SIZE_DSINDEX_NAMES | MAGIC_SIZE_TYPE_NAMES\ + | MAGIC_SIZE_MEMBER_NAMES | MAGIC_SIZE_COMP_TYPES) + +#endif + +/* Magic reentrant functions. */ +PUBLIC void magic_reentrant_enable(void); +PUBLIC void magic_reentrant_disable(void); diff --git a/minix/llvm/include/magic_analysis.h b/minix/llvm/include/magic_analysis.h new file mode 100644 index 000000000..645a266ab --- /dev/null +++ b/minix/llvm/include/magic_analysis.h @@ -0,0 +1,427 @@ +#ifndef _MAGIC_ANALYSIS_H +#define _MAGIC_ANALYSIS_H + +#include +#include + +/* Special convenience types. */ +#define MAGIC_TYPE_SPECIAL_INIT(STR) { 0, STR, NULL, 0, STR, 0, 0, 0, 0, 0, 0, \ + 0, MAGIC_TYPE_FUNCTION, MAGIC_TYPE_EXTERNAL, 0 } +EXTERN char magic_ne_str[]; +EXTERN char magic_enf_str[]; +EXTERN char magic_bo_str[]; +EXTERN char magic_be_str[]; +EXTERN char magic_bv_str[]; +EXTERN char magic_vf_str[]; +EXTERN const struct _magic_type magic_NULL_ENTRY_TYPE; +EXTERN const struct _magic_type magic_ENTRY_NOT_FOUND_TYPE; +EXTERN const struct _magic_type magic_BAD_OFFSET_TYPE; +EXTERN const struct _magic_type magic_BAD_ENTRY_TYPE; +EXTERN const struct _magic_type magic_BAD_VALUE_TYPE; +EXTERN const struct _magic_type magic_VALUE_FOUND; +#define MAGIC_TYPE_NULL_ENTRY (&magic_NULL_ENTRY_TYPE) +#define MAGIC_TYPE_ENTRY_NOT_FOUND (&magic_ENTRY_NOT_FOUND_TYPE) +#define MAGIC_TYPE_BAD_OFFSET (&magic_BAD_OFFSET_TYPE) +#define MAGIC_TYPE_BAD_ENTRY (&magic_BAD_ENTRY_TYPE) +#define MAGIC_TYPE_BAD_VALUE (&magic_BAD_VALUE_TYPE) +#define MAGIC_TYPE_VALUE_FOUND (&magic_VALUE_FOUND) +#define MAGIC_TYPE_IS_SPECIAL(T) (T == MAGIC_TYPE_NULL_ENTRY \ + || T == MAGIC_TYPE_ENTRY_NOT_FOUND || T == MAGIC_TYPE_BAD_OFFSET \ + || T == MAGIC_TYPE_BAD_ENTRY || T == MAGIC_TYPE_BAD_VALUE \ + || T == MAGIC_TYPE_VALUE_FOUND) + +/* Magic state element macros. */ +#define MAGIC_SEL_ANALYZE_POINTERS 0x00001 +#define MAGIC_SEL_ANALYZE_NONPOINTERS 0x00002 +#define MAGIC_SEL_ANALYZE_LIKELYPOINTERS 0x00004 +#define MAGIC_SEL_ANALYZE_DATA 0x00008 +#define MAGIC_SEL_ANALYZE_INVARIANTS 0x00010 +#define MAGIC_SEL_ANALYZE_VIOLATIONS 0x00020 +#define MAGIC_SEL_ANALYZE_WALKABLE 0x00040 +#define MAGIC_SEL_ANALYZE_DYNAMIC 0x00080 +#define MAGIC_SEL_ANALYZE_OUT_OF_BAND 0x00100 +#define MAGIC_SEL_ANALYZE_LIB_SRC 0x00200 +#define MAGIC_SEL_ANALYZE_ALL \ + (MAGIC_SEL_ANALYZE_POINTERS | MAGIC_SEL_ANALYZE_NONPOINTERS \ + | MAGIC_SEL_ANALYZE_DATA | MAGIC_SEL_ANALYZE_INVARIANTS \ + | MAGIC_SEL_ANALYZE_VIOLATIONS | MAGIC_SEL_ANALYZE_WALKABLE \ + | MAGIC_SEL_ANALYZE_DYNAMIC | MAGIC_SEL_ANALYZE_OUT_OF_BAND \ + | MAGIC_SEL_ANALYZE_LIB_SRC) + +#define MAGIC_SEL_SKIP_UNIONS 0x00400 +#define MAGIC_SEL_SKIP_INTEGERS 0x00800 +#define MAGIC_SEL_ANALYZE_NONPTRS_AS_PTRS 0x01000 +#define MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS 0x02000 + +#define MAGIC_SEL_FOUND_DATA 0x04000 +#define MAGIC_SEL_FOUND_INVARIANTS 0x08000 +#define MAGIC_SEL_FOUND_VIOLATIONS 0X10000 +#define MAGIC_SEL_FOUND_WALKABLE 0x20000 + +/* Magic state element analyzed. */ +typedef enum { + _ptr_type_found, + _other_types_found, + _void_type_found, + _comp_trg_types_found, + _badentry_found +} _magic_trg_stats_t; +struct _magic_sel_analyzed_s { + unsigned type_id, contained_type_id; + int flags; + int num; + union { + struct { + void *value; + union { + struct _magic_dsentry dsentry; + struct _magic_dfunction dfunction; + } trg; + struct { + struct _magic_dsentry *dsentry; + struct _magic_dfunction *dfunction; + } trg_p; + int trg_flags; + int trg_offset; + _magic_selement_t trg_selements[MAGIC_MAX_RECURSIVE_TYPES + 1]; + _magic_trg_stats_t trg_stats[MAGIC_MAX_RECURSIVE_TYPES + 1]; + int first_legal_trg_type; + unsigned num_legal_trg_types; + unsigned num_trg_types; + } ptr; + struct { + int value; + int trg_flags; + } nonptr; + } u; +}; +typedef struct _magic_sel_analyzed_s _magic_sel_analyzed_t; + +#define MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(E) \ + (((E)->u.ptr.trg_flags & MAGIC_STATE_TEXT) != 0) +#define MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(E) \ + ((E)->u.ptr.trg_flags && !MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(E)) +#define MAGIC_SEL_ANALYZED_PTR_SENTRY(E) \ + ((E)->u.ptr.trg_flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS) \ + ? (E)->u.ptr.trg_p.dsentry->sentry \ + : (E)->u.ptr.trg.dsentry.sentry +#define MAGIC_SEL_ANALYZED_PTR_SENTRY_ADDRESS(E) \ + ((E)->u.ptr.trg_flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS) \ + ? &((E)->u.ptr.trg_p.dsentry->sentry) \ + : &((E)->u.ptr.trg.dsentry.sentry) +#define MAGIC_SEL_ANALYZED_PTR_FUNCTION(E) \ + ((E)->u.ptr.trg_flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS) \ + ? (E)->u.ptr.trg_p.dfunction->function \ + : (E)->u.ptr.trg.dfunction.function +#define MAGIC_SEL_ANALYZED_PTR_TRG_NAME(E) \ + (MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(E) ? "" \ + : MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(E) \ + ? (MAGIC_SEL_ANALYZED_PTR_FUNCTION(E)).name \ + : (MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(E) \ + ? (MAGIC_SEL_ANALYZED_PTR_SENTRY(E)).name : "?")) +#define MAGIC_SEL_ANALYZED_PTR_TRG_ADDRESS(E) \ + (MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(E) ? NULL \ + : MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(E) \ + ? (MAGIC_SEL_ANALYZED_PTR_FUNCTION(E)).address \ + : (MAGIC_SEL_ANALYZED_PTR_SENTRY(E)).address) +#define MAGIC_SEL_ANALYZED_PTR_PRINT_TRG_ABS_NAME(E) \ + do { \ + if (MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(E) \ + || MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(E)) { \ + _magic_printf(MAGIC_SEL_ANALYZED_PTR_TRG_NAME(E)); \ + } else { \ + magic_print_sentry_abs_name( \ + MAGIC_SEL_ANALYZED_PTR_SENTRY_ADDRESS(E)); \ + } \ + } while(0) +#define MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(E) \ + ((E)->u.ptr.trg_selements[0].type) +#define MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(E) \ + (MAGIC_TYPE_IS_SPECIAL(MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(E))) +#define MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(E,T) \ + do { \ + (E)->u.ptr.trg_selements[0].type = T; \ + (E)->u.ptr.num_trg_types = 1; \ + (E)->u.ptr.num_legal_trg_types = 0; \ + (E)->u.ptr.first_legal_trg_type = -1; \ + } while(0) +#define MAGIC_SEL_ANALYZED_TRG_FLAGS(E) \ + ((E)->type_id == MAGIC_TYPE_POINTER ? (E)->u.ptr.trg_flags \ + : (E)->u.nonptr.trg_flags) +#define MAGIC_SEL_ANALYZED_FLAG(E,F) (((E)->flags & F) != 0) +#define MAGIC_SEL_ANALYZED_TRG_STATS_HAS_VIOLATIONS(E) \ + ((E) == _other_types_found || (E) == _badentry_found) +#define MAGIC_SEL_ANALYZED_TRG_STATS_C(E) \ + ((E) == _ptr_type_found ? 'p' : (E) == _other_types_found ? 'o' \ + : (E) == _void_type_found ? 'v' : (E) == _comp_trg_types_found ? 'c' \ + : (E) == _badentry_found ? 'b' : '?') + +#define MAGIC_SEL_ANALYZED_PRINT(E, FLAGS) do { \ + _magic_printf("SEL_ANALYZED: (num=%d, type=%s, flags(DIVW)=%d%d%d%d", \ + (E)->num, (E)->type_id == MAGIC_TYPE_POINTER ? "ptr" : "nonptr", \ + MAGIC_SEL_ANALYZED_FLAG(E, MAGIC_SEL_FOUND_DATA), \ + MAGIC_SEL_ANALYZED_FLAG(E, MAGIC_SEL_FOUND_INVARIANTS), \ + MAGIC_SEL_ANALYZED_FLAG(E, MAGIC_SEL_FOUND_VIOLATIONS), \ + MAGIC_SEL_ANALYZED_FLAG(E, MAGIC_SEL_FOUND_WALKABLE)); \ + if((E)->type_id == MAGIC_TYPE_POINTER) { \ + _magic_printf(", value=0x%08x, trg_name=", (E)->u.ptr.value); \ + MAGIC_SEL_ANALYZED_PTR_PRINT_TRG_ABS_NAME(E); \ + _magic_printf(", trg_offset=%d, trg_flags(RL)=%c%c", \ + (E)->u.ptr.trg_offset, \ + (E)->u.ptr.trg_flags \ + ? MAGIC_STATE_FLAGS_REGION_C((E)->u.ptr.trg_flags) : 0, \ + (E)->u.ptr.trg_flags \ + ? MAGIC_STATE_FLAGS_LIBSPEC_C((E)->u.ptr.trg_flags) : 0); \ + if((E)->u.ptr.num_trg_types > 0) { \ + _magic_printf(", trg_selements=("); \ + magic_sel_analyzed_trg_selements_print(E, FLAGS); \ + _magic_printf(")"); \ + } \ + } else { \ + _magic_printf(", value=%d/0x%08x", \ + (E)->u.nonptr.value, (E)->u.nonptr.value); \ + if((E)->u.nonptr.trg_flags) { \ + _magic_printf(", trg_flags(RL)=%c%c", \ + MAGIC_STATE_FLAGS_REGION_C((E)->u.nonptr.trg_flags), \ + MAGIC_STATE_FLAGS_LIBSPEC_C((E)->u.nonptr.trg_flags)); \ + } \ + } \ + _magic_printf(")"); \ + } while(0) + +/* Magic state element stats. */ +struct _magic_sel_stats_s { + unsigned ptr_found; + unsigned nonptr_found; + unsigned nonptr_unconstrained_found; + int trg_flags; + int ptr_type_found; + int other_types_found; + int null_type_found; + int badoffset_found; + int unknown_found; + int void_type_found; + int comp_trg_types_found; + int value_found; + int badvalue_found; + int badentry_found; +}; +typedef struct _magic_sel_stats_s _magic_sel_stats_t; + +/* Magic state element stats. */ +#define MAGIC_SEL_STAT_INCR(S,I,F) ((S)->F += (I)->F) +#define MAGIC_SEL_STATS_INCR(S,I) do { \ + MAGIC_SEL_STAT_INCR(S,I, ptr_found); \ + MAGIC_SEL_STAT_INCR(S,I, nonptr_found); \ + MAGIC_SEL_STAT_INCR(S,I, nonptr_unconstrained_found); \ + S->trg_flags |= I->trg_flags; \ + MAGIC_SEL_STAT_INCR(S,I, ptr_type_found); \ + MAGIC_SEL_STAT_INCR(S,I, other_types_found); \ + MAGIC_SEL_STAT_INCR(S,I, null_type_found); \ + MAGIC_SEL_STAT_INCR(S,I, badoffset_found); \ + MAGIC_SEL_STAT_INCR(S,I, unknown_found); \ + MAGIC_SEL_STAT_INCR(S,I, void_type_found); \ + MAGIC_SEL_STAT_INCR(S,I, comp_trg_types_found); \ + MAGIC_SEL_STAT_INCR(S,I, value_found); \ + MAGIC_SEL_STAT_INCR(S,I, badvalue_found); \ + MAGIC_SEL_STAT_INCR(S,I, badentry_found); \ + } while(0) + +#define MAGIC_SEL_STATS_HAS_VIOLATIONS(S) \ + (MAGIC_SEL_STATS_NUM_VIOLATIONS(S) > 0) +#define MAGIC_SEL_STATS_NUM_VIOLATIONS(S) \ + ((S)->ptr_found ? MAGIC_SEL_PTR_STATS_NUM_VIOLATIONS(S) \ + : MAGIC_SEL_NONPTR_STATS_NUM_VIOLATIONS(S)) +#define MAGIC_SEL_PTR_STATS_NUM_VIOLATIONS(S) ((S)->other_types_found \ + + (S)->badoffset_found + (S)->unknown_found + (S)->badvalue_found \ + + (S)->badentry_found) +#define MAGIC_SEL_NONPTR_STATS_NUM_VIOLATIONS(S) ((S)->badvalue_found) + +#define MAGIC_SEL_STATS_PRINT(E) do { \ + _magic_printf("SEL_STATS: (type=%s", \ + (E)->ptr_found ? "ptr" : "nonptr"); \ + if((E)->trg_flags) { \ + _magic_printf(", trg_flags(RL)=%c%c", \ + MAGIC_STATE_FLAGS_REGION_C((E)->trg_flags), \ + MAGIC_STATE_FLAGS_LIBSPEC_C((E)->trg_flags)); \ + } \ + if((E)->ptr_found) _magic_printf(", ptr_found=%d", (E)->ptr_found); \ + if((E)->nonptr_found) \ + _magic_printf(", nonptr_found=%d", (E)->nonptr_found); \ + if((E)->nonptr_unconstrained_found) \ + _magic_printf(", nonptr_unconstrained_found=%d", \ + (E)->nonptr_unconstrained_found); \ + if((E)->ptr_type_found) \ + _magic_printf(", ptr_type_found=%d", (E)->ptr_type_found); \ + if((E)->other_types_found) \ + _magic_printf(", other_types_found=%d", (E)->other_types_found); \ + if((E)->null_type_found) \ + _magic_printf(", null_type_found=%d", (E)->null_type_found); \ + if((E)->badoffset_found) \ + _magic_printf(", badoffset_found=%d", (E)->badoffset_found); \ + if((E)->unknown_found) \ + _magic_printf(", unknown_found=%d", (E)->unknown_found); \ + if((E)->void_type_found) \ + _magic_printf(", void_type_found=%d", (E)->void_type_found); \ + if((E)->comp_trg_types_found) \ + _magic_printf(", comp_trg_types_found=%d", \ + (E)->comp_trg_types_found); \ + if((E)->value_found) \ + _magic_printf(", value_found=%d", (E)->value_found); \ + if((E)->badvalue_found) \ + _magic_printf(", badvalue_found=%d", (E)->badvalue_found); \ + if((E)->badentry_found) \ + _magic_printf(", badentry_found=%d", (E)->badentry_found); \ + _magic_printf(", violations=%d", MAGIC_SEL_STATS_NUM_VIOLATIONS(E)); \ + _magic_printf(")"); \ + } while(0) + +/* Magic sentry macros. */ +#define MAGIC_SENTRY_ANALYZE_STOP 1 +#define MAGIC_SENTRY_ANALYZE_CONTINUE 2 +#define MAGIC_SENTRY_ANALYZE_SKIP_PATH 3 +#define MAGIC_SENTRY_ANALYZE_IS_VALID_RET(R) \ + ((R)>=MAGIC_SENTRY_ANALYZE_STOP && (R)<=MAGIC_SENTRY_ANALYZE_SKIP_PATH) + +#ifndef __MINIX +#define MAGIC_PTR_LIKELY_INTS_START 0xFFFFF000 +#else +#define MAGIC_PTR_LIKELY_INTS_START 0xE0000000 +#endif +#define MAGIC_PTR_LIKELY_INTS_END 0xFFF +#define MAGIC_PTR_IS_LIKELY_INT(V) \ + ((V) && ((unsigned)(V)>=MAGIC_PTR_LIKELY_INTS_START \ + || (unsigned)(V)<=MAGIC_PTR_LIKELY_INTS_END)) +#define MAGIC_INT_IS_LIKELY_PTR(V) \ + ((V) && !MAGIC_PTR_IS_LIKELY_INT((void*)V)) + +/* Magic callbacks. */ +typedef int (*magic_cb_sentries_analyze_pre_t)(); +PUBLIC void magic_setcb_sentries_analyze_pre(magic_cb_sentries_analyze_pre_t cb); + +/* Magic state entry functions. */ +typedef int (*magic_sentry_analyze_cb_t)(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args); +PUBLIC int magic_sentry_print_ptr_types(struct _magic_sentry* entry); +PUBLIC int magic_sentry_extract_ptrs(struct _magic_sentry* entry, + void ****ptr_map, const struct _magic_type ***ptr_type_map, int *ptr_num); +PUBLIC int magic_sentry_analyze(struct _magic_sentry* sentry, int flags, + const magic_sentry_analyze_cb_t cb, void* cb_args, + _magic_sel_stats_t *sentry_stats); +PUBLIC int magic_sentries_analyze(int flags, const magic_sentry_analyze_cb_t cb, + void* cb_args, _magic_sel_stats_t *sentries_stats); +PUBLIC int magic_sentry_print_selements(struct _magic_sentry* sentry); +PUBLIC int magic_sentry_print_ptr_selements(struct _magic_sentry* sentry, + int skip_null_ptrs, int max_target_recusions); + +/* Magic dynamic state entry functions. */ +PUBLIC int magic_dsentries_analyze(int flags, + const magic_sentry_analyze_cb_t cb, void* cb_args, + _magic_sel_stats_t *dsentries_stats); + +/* Magic sentry analyze callbacks. */ +PUBLIC int magic_sentry_print_el_cb(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args); +PUBLIC int magic_sentry_print_ptr_el_cb(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args); +PUBLIC int magic_sentry_print_el_with_trg_reg_cb(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args); +PUBLIC int magic_sentry_print_el_with_trg_cb(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args); + +/* Magic sentry analyze helpers. */ +#define magic_sentry_analyze_invariants(sentry, cb, cb_args, sentry_stats) \ + magic_sentry_analyze(sentry, MAGIC_SEL_ANALYZE_POINTERS \ + | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_INVARIANTS, cb, \ + cb_args, sentry_stats) +#define magic_sentries_analyze_invariants(cb, cb_args, sentries_stats) \ + magic_sentries_analyze(MAGIC_SEL_ANALYZE_POINTERS \ + | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_INVARIANTS, cb, \ + cb_args, sentries_stats) +#define magic_dsentries_analyze_invariants(cb, cb_args, dsentries_stats) \ + magic_dsentries_analyze(MAGIC_SEL_ANALYZE_POINTERS \ + | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_INVARIANTS, cb, \ + cb_args, dsentries_stats) +#define magic_allsentries_analyze_invariants(cb, cb_args, sentries_stats) \ + magic_sentries_analyze(MAGIC_SEL_ANALYZE_POINTERS \ + | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_INVARIANTS \ + | MAGIC_SEL_ANALYZE_DYNAMIC, cb, cb_args, sentries_stats) + +#define magic_sentry_analyze_violations(sentry, cb, cb_args, sentry_stats) \ + magic_sentry_analyze(sentry, MAGIC_SEL_ANALYZE_POINTERS \ + | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_VIOLATIONS, cb, \ + cb_args, sentry_stats) +#define magic_sentries_analyze_violations(cb, cb_args, sentries_stats) \ + magic_sentries_analyze(MAGIC_SEL_ANALYZE_POINTERS \ + | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_VIOLATIONS, cb, \ + cb_args, sentries_stats) +#define magic_dsentries_analyze_violations(cb, cb_args, dsentries_stats) \ + magic_dsentries_analyze(MAGIC_SEL_ANALYZE_POINTERS \ + | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_VIOLATIONS, cb, \ + cb_args, dsentries_stats) +#define magic_allsentries_analyze_violations(cb, cb_args, sentries_stats) \ + magic_sentries_analyze(MAGIC_SEL_ANALYZE_POINTERS \ + | MAGIC_SEL_ANALYZE_NONPOINTERS | MAGIC_SEL_ANALYZE_VIOLATIONS \ + | MAGIC_SEL_ANALYZE_DYNAMIC, cb, cb_args, sentries_stats) + +#define magic_sentry_analyze_likely_pointers(sentry, cb, cb_args, sentry_stats)\ + magic_sentry_analyze(sentry, MAGIC_SEL_ANALYZE_LIKELYPOINTERS \ + | MAGIC_SEL_ANALYZE_DATA, cb, cb_args, sentry_stats) +#define magic_sentries_analyze_likely_pointers(cb, cb_args, sentries_stats) \ + magic_sentries_analyze(MAGIC_SEL_ANALYZE_LIKELYPOINTERS \ + | MAGIC_SEL_ANALYZE_DATA, cb, cb_args, sentries_stats) +#define magic_dsentries_analyze_likely_pointers(cb, cb_args, dsentries_stats) \ + magic_dsentries_analyze(MAGIC_SEL_ANALYZE_LIKELYPOINTERS \ + | MAGIC_SEL_ANALYZE_DATA, cb, cb_args, dsentries_stats) +#define magic_allsentries_analyze_likely_pointers(cb, cb_args, sentries_stats) \ + magic_sentries_analyze(MAGIC_SEL_ANALYZE_LIKELYPOINTERS \ + | MAGIC_SEL_ANALYZE_DATA | MAGIC_SEL_ANALYZE_DYNAMIC, cb, cb_args, \ + sentries_stats) + +/* Magic state type functions. */ +PUBLIC int magic_type_count_ptrs(const struct _magic_type* type, int *ptr_num); + +/* Magic type walk callbacks. */ +PUBLIC int magic_type_examine_ptr_cb(const struct _magic_type* parent_type, + const unsigned parent_offset, int child_num, const struct _magic_type* type, + const unsigned offset, int depth, void* cb_args); +PUBLIC int magic_type_extract_ptr_cb(const struct _magic_type* parent_type, + const unsigned parent_offset, int child_num, const struct _magic_type* type, + const unsigned offset, int depth, void* cb_args); +PUBLIC int magic_type_analyzer_cb(const struct _magic_type* parent_type, + const unsigned parent_offset, int child_num, const struct _magic_type* type, + const unsigned offset, int depth, void* cb_args); + +/* Magic state element functions. */ +PUBLIC int magic_selement_analyze(_magic_selement_t *selement, int flags, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats); +PUBLIC int magic_selement_analyze_ptr(_magic_selement_t *selement, int flags, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats); +PUBLIC int magic_selement_analyze_nonptr(_magic_selement_t *selement, int flags, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats); +PUBLIC int magic_selement_analyze_ptr_value_invs(_magic_selement_t *selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats); +PUBLIC int magic_selement_analyze_ptr_trg_invs(_magic_selement_t *selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats); +PUBLIC _magic_trg_stats_t +magic_selement_analyze_ptr_target(const struct _magic_type *ptr_type, + const struct _magic_type *trg_type, int trg_flags); +PUBLIC int magic_selement_analyze_ptr_type_invs(_magic_selement_t *selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats); +PUBLIC int magic_selement_recurse_ptr(_magic_selement_t *selement, + _magic_selement_t *new_selement, int max_steps); +PUBLIC void +magic_sel_analyzed_trg_selements_print(_magic_sel_analyzed_t *sel_analyzed, + int flags); +PUBLIC _magic_selement_t* +magic_selement_type_cast(_magic_selement_t *selement, int flags, + const struct _magic_type* type, _magic_sel_analyzed_t *sel_analyzed, + _magic_sel_stats_t *sel_stats); + +#endif /* _MAGIC_ANALYSIS_H */ + diff --git a/minix/llvm/include/magic_asr.h b/minix/llvm/include/magic_asr.h new file mode 100644 index 000000000..5cecde254 --- /dev/null +++ b/minix/llvm/include/magic_asr.h @@ -0,0 +1,11 @@ +#include +#include +#include +#include +#include +#include + +PUBLIC int magic_asr_get_padding_size(int region); +PUBLIC void magic_asr_permute_dsentries(struct _magic_dsentry + **first_dsentry_ptr); +PUBLIC void magic_asr_init(); diff --git a/minix/llvm/include/magic_def.h b/minix/llvm/include/magic_def.h new file mode 100644 index 000000000..67276ccd2 --- /dev/null +++ b/minix/llvm/include/magic_def.h @@ -0,0 +1,188 @@ +#ifndef _MAGIC_DEF_H +#define _MAGIC_DEF_H + +#if defined(_MINIX) || defined(_MINIX_SYSTEM) +#ifndef __MINIX +#define __MINIX 1 +#endif +#endif + +#include + +/* 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 + +#if CUSTOM_ASSERTIONS +#ifdef assert +#undef assert +#endif +#ifndef __ASSERT_FUNCTION +#define __ASSERT_FUNCTION "" +#endif + +#if ENABLE_ASSERTIONS +#define assert(X) do{ \ + if(!(X)) { \ + magic_assert_failed(#X, __FILE__, __ASSERT_FUNCTION, __LINE__); \ + } \ + } while(0) +#else +# define assert(X) +#endif +#endif + +#endif + diff --git a/minix/llvm/include/magic_eval.h b/minix/llvm/include/magic_eval.h new file mode 100644 index 000000000..7dd598ef8 --- /dev/null +++ b/minix/llvm/include/magic_eval.h @@ -0,0 +1,25 @@ +#ifndef _MAGIC_EVAL_H +#define _MAGIC_EVAL_H + +#include + +typedef long (*magic_eval_func_t) (long arg); + +PUBLIC void magic_eval_init(); + +/* Eval frontends. */ +PUBLIC int magic_eval_int(char *expr, long *result); +PUBLIC int magic_eval_bool(char *expr, char *result); +PUBLIC int magic_eval_float(char *expr, double *result); + +/* Printing. */ +#define MAGIC_EVAL_PRINT_FUNC_RESULTS 0x01 +#define MAGIC_EVAL_PRINT_VAR_VALUES 0x02 +#define MAGIC_EVAL_PRINT_STYLE_DEFAULT 0 +#define MAGIC_EVAL_PRINT_STYLE_ALL (MAGIC_EVAL_PRINT_FUNC_RESULTS|MAGIC_EVAL_PRINT_VAR_VALUES) + +PUBLIC int magic_eval_get_print_style(void); +PUBLIC void magic_eval_set_print_style(int style); + +#endif + diff --git a/minix/llvm/include/magic_eval_lib.h b/minix/llvm/include/magic_eval_lib.h new file mode 100644 index 000000000..8b0bb2505 --- /dev/null +++ b/minix/llvm/include/magic_eval_lib.h @@ -0,0 +1,74 @@ +/* evaluate.h (C) 2000-2002 Kyzer/CSG. */ +/* Released under the terms of the GNU General Public Licence version 2. */ +/* http://www.kyzer.me.uk/code/evaluate/ */ + +#include +#include + +#define T_INT 0 +#define T_REAL 1 + +/* value */ +struct val { + long ival; /* if type = T_INT, this is the result */ + double rval; /* if type = T_REAL, this is the result */ + char type; /* either T_INT or T_REAL */ +}; + +/* variable */ +struct var { + struct var *next; /* next variable in table or NULL */ + struct val val; /* value of variable */ + char *name; /* name of variable */ +}; + +/* variable table */ +struct vartable { + struct var *first; /* first entry in variable table */ + struct memh *mh; +}; + +/* creates a new variable table (NULL if no memory) */ +struct vartable *create_vartable(); + +/* frees a variable table */ +void free_vartable(struct vartable *vt); + +/* gets a variable from a variable table (NULL if not found) */ +struct var *get_var(struct vartable *vt, char *name); + +/* puts a variable into a variable table (NULL if no memory) */ +struct var *put_var(struct vartable *vt, char *name, struct val *value); + +/* callbacks */ +typedef struct val*(*get_var_cb_t)(char*, struct val*); +typedef struct val*(*get_func_result_cb_t)(char*, struct val*, struct val*); +void eval_set_cb_get_var(get_var_cb_t cb); +void eval_set_cb_get_func_result(get_func_result_cb_t cb); + +/* THE FUNCTION YOU WANT TO CALL */ + +/* given a string to evaluate (not NULL), a result to put the answer in + * (not NULL) and optionally your own variable table (NULL for 'internal + * only' vartable), will return an error code (and result, etc) + */ +int evaluate(char *eval, struct val *result, struct vartable *variables); + +/* errors */ +#define RESULT_OK 0 /* all OK */ +#define ERROR_SYNTAX 2 /* invalid expression */ +#define ERROR_VARNOTFOUND 3 /* variable not found */ +#define ERROR_FUNCNOTFOUND 4 /* function not found */ +#define ERROR_NOMEM 8 /* not enough memory available */ +#define ERROR_DIV0 9 /* division by zero */ +#define ERROR_BUSY 10 /* busy now */ + +/* configuration */ +#define TOKEN_DEBUG 0 +#define EVAL_DEBUG 0 +#define EVAL_MALLOC 0 +#define USE_MATH_LIB 0 +#define MEM_DEBUG 0 +#define MEM_LOW_FOOTPRINT 1 +#define VAR_FROM_ENV 0 + diff --git a/minix/llvm/include/magic_mem.h b/minix/llvm/include/magic_mem.h new file mode 100644 index 000000000..63fb0309f --- /dev/null +++ b/minix/llvm/include/magic_mem.h @@ -0,0 +1,284 @@ +#ifndef _MAGIC_MEM_H +#define _MAGIC_MEM_H + +#include + +#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 +#ifndef __MINIX +#include +#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 + +#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 + +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 +#include + +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 + +PUBLIC void *magic_vm_map_cacheblock(__MA_ARGS__ dev_t dev, off_t dev_offset, + ino_t ino, off_t ino_offset, u32_t *flags, int blocksize); +PUBLIC void *(*magic_real_vm_map_cacheblock)(dev_t dev, off_t dev_offset, + ino_t ino, off_t ino_offset, u32_t *flags, int blocksize); +#endif + +/* wrappers to skip alloction */ +PUBLIC void *magic_malloc_positioned( __MA_ARGS__ size_t size, void *ptr); +PUBLIC void *magic_mmap_positioned(__MA_ARGS__ void *start, size_t length, int prot, int flags, + int fd, off_t offset, struct _magic_dsentry *cached_dsentry); + +/* Macros. */ +#define MAGIC_ALLOC_SIZE (sizeof(struct _magic_dsentry)) + +#define MAGIC_SIZE_TO_REAL(S) (S + MAGIC_ALLOC_SIZE) +#define MAGIC_SIZE_TO_SOURCE(S) (S - MAGIC_ALLOC_SIZE) +#define MAGIC_PTR_TO_DSENTRY(P) \ + ((struct _magic_dsentry *) (((char *)P))) +#define MAGIC_PTR_FROM_DSENTRY(P) ((void *) P) +#define MAGIC_PTR_TO_DATA(P) \ + ((void *) (((char *)P) + MAGIC_ALLOC_SIZE)) +#define MAGIC_PTR_FROM_DATA(P) \ + ((void *) (((char *)P) - MAGIC_ALLOC_SIZE)) + +/* Variables to keep track of magic mem wrappers. */ +EXTERN THREAD_LOCAL short magic_mem_wrapper_active; +EXTERN short magic_mem_create_dsentry_site_id; + +/* Variables to indicate if dsentry site_ids should be created. */ + +#if MAGIC_ALLOW_DYN_MEM_WRAPPER_NESTING +#define MAGIC_MEM_WRAPPER_IS_ACTIVE() (magic_mem_wrapper_active > 0) +#define MAGIC_MEM_WRAPPER_BEGIN() do { \ + magic_mem_wrapper_active++; \ + } while(0) +#define MAGIC_MEM_WRAPPER_END() do { \ + assert(MAGIC_MEM_WRAPPER_IS_ACTIVE()); \ + magic_mem_wrapper_active--; \ + } while(0) +#else +#define MAGIC_MEM_WRAPPER_IS_ACTIVE() (magic_mem_wrapper_active == 1) +#define MAGIC_MEM_WRAPPER_BEGIN() do { \ + assert(!MAGIC_MEM_WRAPPER_IS_ACTIVE()); \ + magic_mem_wrapper_active = 1; \ + } while(0) +#define MAGIC_MEM_WRAPPER_END() do { \ + assert(MAGIC_MEM_WRAPPER_IS_ACTIVE()); \ + magic_mem_wrapper_active = 0; \ + } while(0) +#endif + +#define MAGIC_MEM_WRAPPER_LBEGIN() do { \ + MAGIC_MEM_WRAPPER_BEGIN(); \ + MAGIC_DSENTRY_LOCK(); \ + } while(0) +#define MAGIC_MEM_WRAPPER_LEND() do { \ + MAGIC_MEM_WRAPPER_END(); \ + MAGIC_DSENTRY_UNLOCK(); \ + } while(0) +#define MAGIC_MEM_WRAPPER_BLOCK(BLOCK) do { \ + MAGIC_MEM_WRAPPER_BEGIN(); \ + BLOCK \ + MAGIC_MEM_WRAPPER_END(); \ + } while(0) +#define MAGIC_MEM_WRAPPER_LBLOCK(BLOCK) do { \ + MAGIC_MEM_WRAPPER_LBEGIN(); \ + BLOCK \ + MAGIC_MEM_WRAPPER_LEND(); \ + } while(0) + +/* Variables to keep track of memory pool management functions. */ +#define MAGIC_MEMPOOL_ID_UNKNOWN -1 +#define MAGIC_MEMPOOL_ID_DETACHED -2 +#define MAGIC_MEMPOOL_MAX_FUNC_RECURSIONS 100 +EXTERN THREAD_LOCAL short magic_mempool_mgmt_active_level; +EXTERN THREAD_LOCAL short magic_mempool_ids[MAGIC_MEMPOOL_MAX_FUNC_RECURSIONS]; +EXTERN int magic_mempool_allow_reset; +EXTERN int magic_mempool_allow_reuse; + +/* TLS flags to be set when pool management functions are active. */ +#define MAGIC_MEMPOOL_MGMT_SET_ACTIVE() \ + assert((++magic_mempool_mgmt_active_level <= MAGIC_MEMPOOL_MAX_FUNC_RECURSIONS) \ + && "Reached the maximum number of nested pool function calls!") +#define MAGIC_MEMPOOL_MGMT_IS_ACTIVE() \ + (magic_mempool_mgmt_active_level > 0) +#define MAGIC_MEMPOOL_MGMT_UNSET_ACTIVE() \ + assert((--magic_mempool_mgmt_active_level >= 0) && "Invalid nested pool call level!") +#define MAGIC_MEMPOOL_SET_ID(ID) \ + (magic_mempool_ids[magic_mempool_mgmt_active_level - 1] = ID) +#define MAGIC_MEMPOOL_GET_ID() \ + (magic_mempool_ids[magic_mempool_mgmt_active_level - 1]) +#define MAGIC_MEMPOOL_ID_IS_SET() \ + (magic_mempool_ids[magic_mempool_mgmt_active_level - 1] > 0) +#define MAGIC_MEMPOOL_GET_NAME() \ + (MAGIC_MEMPOOL_ID_IS_SET() ? \ + _magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1].name : \ + ((MAGIC_MEMPOOL_GET_ID() == MAGIC_MEMPOOL_ID_UNKNOWN) ? \ + MAGIC_MEMPOOL_NAME_UNKNOWN : MAGIC_MEMPOOL_NAME_DETACHED)) +/* Store dynamic type in TLS if memory usage logging is enabled */ +#if MAGIC_MEM_USAGE_OUTPUT_CTL +#define MAGIC_MEMPOOL_SET_DTYPE(TYPE) \ + do { \ + if (MAGIC_MEMPOOL_ID_IS_SET()) { \ + _magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1].dtype_id = TYPE; \ + } \ + } while(0) +#define MAGIC_MEMPOOL_GET_DTYPE() \ + (MAGIC_MEMPOOL_ID_IS_SET() ? \ + _magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1].dtype_id : 0) +#else +#define MAGIC_MEMPOOL_SET_DTYPE(TYPE) +#define MAGIC_MEMPOOL_GET_DTYPE() 0 +#endif + +/* Pass call site information when logging is activated. */ +#if (MAGIC_MEM_USAGE_OUTPUT_CTL == 1) +#define __MDEBUG_ARGS__ char* name +#else +#define __MDEBUG_ARGS__ +#endif +/* Specific wrapper for the memory pool creation. */ +MAGIC_HOOK void magic_mempool_create_begin(__MDEBUG_ARGS__); +MAGIC_HOOK void magic_mempool_create_end(void* addr, int indirection); + +/* Specific wrappers for the memory pool destruction. */ +MAGIC_HOOK void magic_mempool_destroy_begin(void* addr, int memory_reuse); +MAGIC_HOOK void magic_mempool_destroy_end(); + +/* Specific wrappers for the memory pool resetting */ +MAGIC_HOOK void magic_mempool_reset_begin(void* addr); + +/* Generic wrappers for the rest of the memory pool management functions. */ +MAGIC_HOOK void magic_mempool_mgmt_begin(void* addr); +MAGIC_HOOK void magic_mempool_mgmt_end(); + +/* Pool block allocation template function and magic wrapper. */ +MAGIC_FUNC void *mempool_block_alloc_template(void* addr, size_t size); +PUBLIC void *magic_mempool_block_alloc_template(__MA_ARGS__ void* addr, size_t size); + +#endif + diff --git a/minix/llvm/include/magic_range.h b/minix/llvm/include/magic_range.h new file mode 100644 index 000000000..ce3a0baea --- /dev/null +++ b/minix/llvm/include/magic_range.h @@ -0,0 +1,100 @@ +#ifndef _MAGIC_RANGE_H +#define _MAGIC_RANGE_H + +#include +#include +#include +#include + +/* Magic memory ranges */ +#define magic_null_range _magic_vars->null_range +#define magic_data_range _magic_vars->data_range +#define magic_heap_range _magic_vars->heap_range +#define magic_map_range _magic_vars->map_range +#define magic_shm_range _magic_vars->shm_range +#define magic_stack_range _magic_vars->stack_range +#define magic_text_range _magic_vars->text_range + +#define magic_sentry_range _magic_vars->sentry_range +#define magic_function_range _magic_vars->function_range +#define magic_dfunction_range _magic_vars->dfunction_range + +#define magic_heap_start _magic_vars->heap_start +#define magic_heap_end _magic_vars->heap_end +#define magic_update_dsentry_ranges _magic_vars->update_dsentry_ranges +#define magic_update_dfunction_ranges _magic_vars->update_dfunction_ranges + +/* Magic address ranges. */ +#define MAGIC_ADDR_IS_WITHIN(A, MIN, MAX) ((MIN) <= (A) && (A) <= (MAX)) +#define MAGIC_ADDR_IS_IN_RANGE(A, R) \ + MAGIC_ADDR_IS_WITHIN(A, (R)[0], (R)[1]) +#define MAGIC_RANGE_IS_IN_RANGE(r, R) \ + (MAGIC_ADDR_IS_IN_RANGE((r)[0], R) && MAGIC_ADDR_IS_IN_RANGE((r)[1], R)) +#define MAGIC_RANGE_COPY(RS, RD) memcpy(RD, RS, 2 * sizeof(void *)) +#define MAGIC_RANGE_INIT(R) MAGIC_RANGE_COPY(magic_null_range,R) +#define MAGIC_RANGE_IS_NULL(R) \ + ((R)[0] == magic_null_range[0] && (R)[1] == magic_null_range[1]) +#define MAGIC_RANGE_IS_VALID(R) \ + (MAGIC_RANGE_IS_NULL(R) || ((R)[0] <= (R)[1])) +#define MAGIC_RANGE_UPDATE(R, MIN, MAX) \ + do { \ + if(MIN < (R)[0]) \ + (R)[0] = MIN; \ + if(MAX > (R)[1]) \ + (R)[1] = MAX; \ + } while(0) +#define MAGIC_RANGE_SET_MIN(R, MIN) ((R)[0] = MIN) +#define MAGIC_RANGE_SET_MAX(R, MAX) ((R)[1] = MAX) +#define MAGIC_RANGE_SET(R, MIN, MAX) \ + do { \ + MAGIC_RANGE_SET_MIN(R, MIN); \ + MAGIC_RANGE_SET_MAX(R, MAX); \ + } while(0) +#define MAGIC_RANGE_PAGE_ROUND_MIN(R) \ + ((R)[0] = (char*)(R)[0] - (unsigned long)(R)[0] % MAGIC_PAGE_SIZE) +#define MAGIC_RANGE_PAGE_ROUND_MAX(R) \ + do { \ + unsigned long diff = (unsigned long)(R)[1] % MAGIC_PAGE_SIZE; \ + if(diff) \ + (R)[1] = (char *)(R)[1] + MAGIC_PAGE_SIZE - diff - 1; \ + } while(0) +#define MAGIC_RANGE_PAGE_ROUND(R) \ + do { \ + MAGIC_RANGE_PAGE_ROUND_MIN(R); \ + MAGIC_RANGE_PAGE_ROUND_MAX(R); \ + } while(0) +#define MAGIC_RANGE_PRINT(R) \ + _magic_printf("RANGE %s=[0x%08x;0x%08x]", #R, (unsigned long)((R)[0]), \ + (unsigned long)((R)[1])) +#define MAGIC_RANGE_CHECK(R) \ + assert(MAGIC_RANGE_IS_VALID(R) && "Invalid range " #R); +#define MAGIC_RANGE_SIZE(R) \ + (!MAGIC_RANGE_IS_VALID(R) || MAGIC_RANGE_IS_NULL(R) ? \ + 0 : (char *)(R)[1] - (char *)(R)[0]) + +#if MAGIC_RANGE_DEBUG +#define MAGIC_RANGE_DEBUG_ADDR(A, R) \ + do { \ + char *what = MAGIC_ADDR_IS_IN_RANGE(A, R) ? "" : "not "; \ + _magic_printf("MRD: Address 0x%08x %sin ", A, what); \ + MAGIC_RANGE_PRINT(R); \ + _magic_printf("\n"); \ + MAGIC_RANGE_CHECK(R); \ + } while(0); +#else +#define MAGIC_RANGE_DEBUG_ADDR(A,R) MAGIC_RANGE_CHECK(R) +#endif + +#define MAGIC_ADDR_LOOKUP_USE_DSENTRY_RANGES 1 +#define MAGIC_ADDR_LOOKUP_USE_DFUNCTION_RANGES 1 + +/* Magic range functions. */ +PUBLIC void magic_ranges_init(void); +PUBLIC int magic_range_is_dfunction(void* addr); +PUBLIC int magic_range_is_dsentry(void* addr); +PUBLIC int magic_range_is_stack(void* addr); + +/* Lookup functions. */ +PUBLIC int magic_range_lookup_by_addr(void *addr, void **container); + +#endif /* _MAGIC_RANGE_H */ diff --git a/minix/llvm/include/magic_rcu.h b/minix/llvm/include/magic_rcu.h new file mode 100644 index 000000000..76c39025b --- /dev/null +++ b/minix/llvm/include/magic_rcu.h @@ -0,0 +1,19 @@ +#ifndef _MAGIC_RCU_H +#define _MAGIC_RCU_H + +void magic_rcu_quiescent_begin(); +void magic_rcu_quiescent_end(); +void magic_rcu_quiescent_state(); +void magic_rcu_quiescent_state_start(); +void magic_rcu_quiescent_state_end(); + +void magic_rcu_init(); +void magic_synchronize_rcu(); + +void magic_rcu_read_lock(); +void magic_rcu_read_unlock(); + +#define magic_rcu_has_atomic_quiescent_state() magic_rcu_has_atomic_qs +extern int magic_rcu_has_atomic_qs; + +#endif /* _MAGIC_RCU_H */ diff --git a/minix/llvm/include/magic_real_mem.h b/minix/llvm/include/magic_real_mem.h new file mode 100644 index 000000000..1826fc291 --- /dev/null +++ b/minix/llvm/include/magic_real_mem.h @@ -0,0 +1,28 @@ +#ifndef _MAGIC_REAL_MEM_H +#define _MAGIC_REAL_MEM_H + +#include + +#define malloc magic_real_malloc +#define calloc magic_real_calloc +#define free magic_real_free +#define realloc magic_real_realloc + +#define posix_memalign magic_real_posix_memalign +#define valloc magic_real_valloc +#define memalign magic_real_memalign + +#define mmap magic_real_mmap +#define munmap magic_real_munmap + +#define brk magic_real_brk +#define sbrk magic_real_sbrk + +#define shmat magic_real_shmat +#define shmdt magic_real_shmdt + +#define mmap64 magic_real_mmap64 +#define vm_map_cacheblock magic_real_vm_map_cacheblock + +#endif + diff --git a/minix/llvm/include/magic_selement.h b/minix/llvm/include/magic_selement.h new file mode 100644 index 000000000..40746c080 --- /dev/null +++ b/minix/llvm/include/magic_selement.h @@ -0,0 +1,53 @@ +#ifndef _MAGIC_SELEMENT_H +#define _MAGIC_SELEMENT_H + +#include +#include +#include +#include +#include + +/* Magic state element functions. */ +PUBLIC void magic_selement_print_value(const _magic_selement_t *selement); +PUBLIC unsigned long + magic_selement_to_unsigned(const _magic_selement_t *selement); +PUBLIC long magic_selement_to_int(const _magic_selement_t *selement); +#if MAGIC_LONG_LONG_SUPPORTED +PUBLIC unsigned long long + magic_selement_to_llu(const _magic_selement_t *selement); +PUBLIC long long magic_selement_to_ll(const _magic_selement_t *selement); +#endif +PUBLIC double magic_selement_to_float(const _magic_selement_t *selement); +PUBLIC void* magic_selement_to_ptr(const _magic_selement_t *selement); +PUBLIC void magic_selement_from_unsigned(const _magic_selement_t *selement, + unsigned long value); +PUBLIC void magic_selement_from_int(const _magic_selement_t *selement, + long value); +PUBLIC void magic_selement_from_float(const _magic_selement_t *selement, + double value); +PUBLIC int magic_selement_ptr_value_cast(const _magic_selement_t *src_selement, + const _magic_selement_t *dst_selement, void* value_buffer); +PUBLIC int +magic_selement_unsigned_value_cast(const _magic_selement_t *src_selement, + const _magic_selement_t *dst_selement, void* value_buffer); +PUBLIC int magic_selement_int_value_cast(const _magic_selement_t *src_selement, + const _magic_selement_t *dst_selement, void* value_buffer); +PUBLIC int +magic_selement_float_value_cast(const _magic_selement_t *src_selement, + const _magic_selement_t *dst_selement, void* value_buffer); +PUBLIC int magic_selement_value_cast(const _magic_selement_t *src_selement, + const _magic_selement_t *dst_selement, void* value_buffer); +PUBLIC _magic_selement_t* +magic_selement_get_parent(const _magic_selement_t *selement, + _magic_selement_t *parent_selement); +PUBLIC void magic_selement_fill_from_parent_info(_magic_selement_t *selement, + int walk_flags); +PUBLIC _magic_selement_t* +magic_selement_from_sentry(struct _magic_sentry *sentry, + _magic_selement_t *selement); +PUBLIC _magic_selement_t* +magic_selement_from_relative_name(_magic_selement_t *parent_selement, + _magic_selement_t *selement, char* name); + + +#endif /* _MAGIC_SELEMENT_H */ diff --git a/minix/llvm/include/magic_sentry.h b/minix/llvm/include/magic_sentry.h new file mode 100644 index 000000000..de3928e01 --- /dev/null +++ b/minix/llvm/include/magic_sentry.h @@ -0,0 +1,181 @@ +#ifndef _MAGIC_SENTRY_H +#define _MAGIC_SENTRY_H + +#include +#include +#include +#include +#include + +/* Magic state entry macros. */ +#define MAGIC_SENTRY_SITE_ID(E) \ + (MAGIC_STATE_FLAG(E, MAGIC_STATE_DYNAMIC) ? \ + MAGIC_DSENTRY_FROM_SENTRY(E)->site_id : MAGIC_DSENTRY_SITE_ID_NULL) +#define MAGIC_SENTRY_PARENT(E) \ + (MAGIC_STATE_FLAG(E, MAGIC_STATE_DYNAMIC) ? \ + MAGIC_DSENTRY_FROM_SENTRY(E)->parent_name : "") +#define MAGIC_SENTRY_ID(E) ((E)->id) +#define MAGIC_SENTRY_IS_STRING(E) MAGIC_STATE_FLAG(E,MAGIC_STATE_STRING) +#define MAGIC_SENTRY_IS_NAMED_STRING(E) \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_NAMED_STRING) +#define MAGIC_SENTRY_IS_DSENTRY(E) MAGIC_STATE_FLAG(E,MAGIC_STATE_DYNAMIC) +/* XXX: Be careful when negating the following macros! */ +#define MAGIC_SENTRY_IS_ALLOC(E) \ + (MAGIC_SENTRY_IS_DSENTRY(E) && !MAGIC_STATE_FLAG(E,MAGIC_STATE_STACK)) +#define MAGIC_SENTRY_IS_EXT_ALLOC(E) \ + (MAGIC_SENTRY_IS_ALLOC(E) && !strcmp((E)->name, MAGIC_ALLOC_EXT_NAME) && \ + !strcmp(MAGIC_DSENTRY_FROM_SENTRY(E)->parent_name, \ + MAGIC_ALLOC_EXT_PARENT_NAME)) +#define MAGIC_SENTRY_IS_LIB_ALLOC(E) \ + (MAGIC_SENTRY_IS_ALLOC(E) && \ + !strncmp((E)->name, MAGIC_ALLOC_EXT_NAME, strlen(MAGIC_ALLOC_EXT_NAME)) && \ + strlen((E)->name) > strlen(MAGIC_ALLOC_EXT_NAME)) +#define MAGIC_SENTRY_PRINT(E, EXPAND_TYPE_STR) do { \ + _magic_printf("SENTRY: (id=%5lu, name=%s, parent=%s, address=0x%08x, " \ + "flags(RLDCdeTAOSNrwxtpbEZIiP)=" \ + "%c%c%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d, type=", \ + (unsigned long) MAGIC_SENTRY_ID(E), (E)->name, \ + MAGIC_SENTRY_PARENT(E), (unsigned) (E)->address, \ + MAGIC_STATE_REGION_C(E), MAGIC_STATE_LIBSPEC_C(E), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_DIRTY), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_CONSTANT), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_DYNAMIC), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_EXT), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_DETACHED), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_ADDR_NOT_TAKEN), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_OUT_OF_BAND), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_STRING), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_NAMED_STRING), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_MODE_R), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_MODE_W), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_MODE_X), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_THREAD_LOCAL), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_MEMPOOL), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_MEMBLOCK), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_EXTERNAL), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_TYPE_SIZE_MISMATCH), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_IMMUTABLE), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_INIT), \ + MAGIC_STATE_FLAG(E,MAGIC_STATE_DIRTY_PAGE)); \ + MAGIC_TYPE_PRINT((E)->type, EXPAND_TYPE_STR); \ + _magic_printf(")"); \ + } while(0) + +#define MAGIC_SENTRY_OFF_BY_N_NO_DUPLICATES 0x01 +#define MAGIC_SENTRY_OFF_BY_N_POSITIVE 0x02 +#define MAGIC_SENTRY_OFF_BY_N_NEGATIVE 0x04 +#define MAGIC_SENTRY_OFF_BY_N_ZERO 0x08 +#define MAGIC_SENTRY_OFF_BY_N_ALL_N (MAGIC_SENTRY_OFF_BY_N_POSITIVE | \ + MAGIC_SENTRY_OFF_BY_N_NEGATIVE | MAGIC_SENTRY_OFF_BY_N_ZERO) + +/* Magic state entry array. */ +#define _magic_sentries (_magic_vars->sentries) +#define _magic_sentries_num (_magic_vars->sentries_num) +#define _magic_sentries_str_num (_magic_vars->sentries_str_num) +#define _magic_sentries_next_id (_magic_vars->sentries_next_id) + +/* Range lookup index */ +#define magic_sentry_rl_buff (_magic_vars->sentry_rl_buff) +#define magic_sentry_rl_buff_offset (_magic_vars->sentry_rl_buff_offset) +#define magic_sentry_rl_buff_size (_magic_vars->sentry_rl_buff_size) +#define magic_sentry_rl_index (_magic_vars->sentry_rl_index) + +/* Hash vars */ +#define magic_sentry_hash_buff (_magic_vars->sentry_hash_buff) +#define magic_sentry_hash_buff_offset (_magic_vars->sentry_hash_buff_offset) +#define magic_sentry_hash_buff_size (_magic_vars->sentry_hash_buff_size) +#define magic_sentry_hash_head (_magic_vars->sentry_hash_head) + +/* Estimated maximum number of buckets needed. Increase as necessary. */ +#define MAGIC_SENTRY_NAME_EST_MAX_BUCKETS 32768 +/* + * Since we don't support freeing memory, we need to allocate _all_ the + * intermediate buckets as well. For simplicity, just assume 1 + 2 + 4 + ... + * + 2^n, though it will probably be less than that. + */ +#define MAGIC_SENTRY_NAME_EST_TOTAL_BUCKETS \ + ((MAGIC_SENTRY_NAME_EST_MAX_BUCKETS << 1) - 1) +#define MAGIC_SENTRY_NAME_HASH_OVERHEAD \ + (MAGIC_SENTRY_NAME_EST_TOTAL_BUCKETS * sizeof(UT_hash_bucket) + \ + sizeof(UT_hash_table)) + +#define MAGIC_SENTRY_TO_HASH_EL(sentry, sentry_hash, sentry_list) \ + do { \ + assert(strlen(sentry->name) + 2 * strlen(MAGIC_DSENTRY_ABS_NAME_SEP) \ + + 2 < MAGIC_SENTRY_NAME_MAX_KEY_LEN \ + && "Sentry key length too long!"); \ + \ + sentry_hash->key[0] = 0; \ + sprintf(sentry_hash->key, "%s%s%s" MAGIC_ID_FORMAT, \ + MAGIC_DSENTRY_ABS_NAME_SEP, sentry->name, \ + MAGIC_DSENTRY_ABS_NAME_SEP, \ + (_magic_id_t) MAGIC_DSENTRY_SITE_ID_NULL); \ + sentry_list->sentry = sentry; \ + sentry_hash->sentry_list = sentry_list; \ + } while (0) + +#define MAGIC_DSENTRY_TO_HASH_EL(dsentry, sentry, sentry_hash, sentry_list) \ + do { \ + assert(strlen(sentry->name) + strlen(dsentry->parent_name) \ + + 2 * strlen(MAGIC_DSENTRY_ABS_NAME_SEP) \ + + 10 + \ + + 1 < MAGIC_SENTRY_NAME_MAX_KEY_LEN \ + && "Dsentry key length too long!"); \ + \ + sentry_hash->key[0] = 0; \ + sprintf(sentry_hash->key, "%s%s%s%s" MAGIC_ID_FORMAT, \ + dsentry->parent_name, MAGIC_DSENTRY_ABS_NAME_SEP, sentry->name, \ + MAGIC_DSENTRY_ABS_NAME_SEP, dsentry->site_id); \ + sentry_list->sentry = sentry; \ + sentry_hash->sentry_list = sentry_list; \ + } while (0) + +/* Lookup functions. */ +PUBLIC struct _magic_sentry *magic_sentry_lookup_by_id(_magic_id_t id, + struct _magic_dsentry *dsentry_buff); +PUBLIC struct _magic_sentry *magic_sentry_lookup_by_addr(void *addr, + struct _magic_dsentry *dsentry_buff); +PUBLIC struct _magic_sentry *magic_sentry_lookup_by_name(char *parent_name, + char *name, _magic_id_t site_id, struct _magic_dsentry *dsentry_buff); +PUBLIC struct _magic_sentry *magic_sentry_lookup_by_range(void *addr, + struct _magic_dsentry *dsentry_buff); +PUBLIC struct _magic_sentry *magic_sentry_lookup_by_min_off_by_n(void *addr, + int flags, long *min_n_ptr, struct _magic_dsentry *dsentry_buff); +PUBLIC struct _magic_sentry *magic_sentry_lookup_by_string(char *string); + +/* Lookup index functions. */ +PUBLIC void magic_sentry_rl_build_index(void *buff, size_t buff_size); +PUBLIC void magic_sentry_rl_destroy_index(void); +PUBLIC size_t magic_sentry_rl_estimate_index_buff_size(int sentries_num); +PUBLIC void magic_sentry_rl_print_index(void); +PUBLIC struct _magic_sentry *magic_sentry_rl_lookup(void* start_addr); +PUBLIC struct _magic_sentry *magic_sentry_rl_insert(void* start_addr, + struct _magic_sentry *sentry); +PUBLIC struct _magic_sentry *magic_sentry_rl_pred_lookup(void* addr); +PUBLIC struct _magic_sentry *magic_sentry_lookup_by_range_index(void *addr, + struct _magic_dsentry *dsentry_buff); + +/* Lookup hash functions. */ +PUBLIC void magic_sentry_hash_build(void *buff, size_t buff_size); +PUBLIC void magic_sentry_hash_destroy(void); +PUBLIC size_t magic_sentry_hash_estimate_buff_size(int sentries_num); +PUBLIC struct _magic_sentry *magic_sentry_lookup_by_name_hash(char *parent_name, + char *name, _magic_id_t site_id, struct _magic_dsentry *dsentry_buff); +PUBLIC void *magic_sentry_hash_alloc(size_t size); +PUBLIC void magic_sentry_hash_dealloc(void *object, size_t size); +PUBLIC struct _magic_sentry_list *magic_sentry_list_lookup_by_name_hash( + char *parent_name, char *name, _magic_id_t site_id, + struct _magic_dsentry *dsentry_buff); + +/* Magic state entry functions. */ +PUBLIC int magic_check_sentry(struct _magic_sentry *entry); +PUBLIC int magic_check_sentries(); +PUBLIC void magic_print_sentry(struct _magic_sentry* entry); +PUBLIC void magic_print_sentry_abs_name(struct _magic_sentry *sentry); +PUBLIC void magic_print_sentries(); +PUBLIC void magic_print_nonstr_sentries(); +PUBLIC void magic_print_str_sentries(); +PUBLIC long magic_sentry_get_off_by_n(struct _magic_sentry* sentry, + void *addr, int flags); + +#endif /* _MAGIC_SENTRY_H */ diff --git a/minix/llvm/include/magic_splay_tree.h b/minix/llvm/include/magic_splay_tree.h new file mode 100644 index 000000000..921195b57 --- /dev/null +++ b/minix/llvm/include/magic_splay_tree.h @@ -0,0 +1,147 @@ +/* A splay-tree datatype. + Copyright 1998, 1999, 2000, 2002 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* For an easily readable description of splay-trees, see: + + Lewis, Harry R. and Denenberg, Larry. Data Structures and Their + Algorithms. Harper-Collins, Inc. 1991. + + The major feature of splay trees is that all basic tree operations + are amortized O(log n) time for a tree with n nodes. */ + +#ifndef _SPLAY_TREE_H +#define _SPLAY_TREE_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef GTY +#define GTY(X) +#endif + +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif /* ATTRIBUTE_UNUSED */ + +/* Use typedefs for the key and data types to facilitate changing + these types, if necessary. These types should be sufficiently wide + that any pointer or scalar can be cast to these types, and then + cast back, without loss of precision. */ +typedef unsigned long int splay_tree_key; +typedef unsigned long int splay_tree_value; + +/* Forward declaration for a node in the tree. */ +typedef struct splay_tree_node_s *splay_tree_node; + +/* The type of a function which compares two splay-tree keys. The + function should return values as for qsort. */ +typedef int (*splay_tree_compare_fn) (splay_tree_key, splay_tree_key); + +/* The type of a function used to deallocate any resources associated + with the key. */ +typedef void (*splay_tree_delete_key_fn) (splay_tree_key); + +/* The type of a function used to deallocate any resources associated + with the value. */ +typedef void (*splay_tree_delete_value_fn) (splay_tree_value); + +/* The type of a function used to iterate over the tree. */ +typedef int (*splay_tree_foreach_fn) (splay_tree_node, void*); + +/* The type of a function used to allocate memory for tree root and + node structures. The first argument is the number of bytes needed; + the second is a data pointer the splay tree functions pass through + to the allocator. This function must never return zero. */ +typedef void *(*splay_tree_allocate_fn) (int, void *); + +/* The type of a function used to free memory allocated using the + corresponding splay_tree_allocate_fn. The first argument is the + memory to be freed; the latter is a data pointer the splay tree + functions pass through to the freer. */ +typedef void (*splay_tree_deallocate_fn) (void *, void *); + +/* The nodes in the splay tree. */ +struct splay_tree_node_s GTY(()) +{ + /* The key. */ + splay_tree_key GTY ((use_param1)) key; + + /* The value. */ + splay_tree_value GTY ((use_param2)) value; + + /* The left and right children, respectively. */ + splay_tree_node GTY ((use_params)) left; + splay_tree_node GTY ((use_params)) right; +}; + +/* The splay tree itself. */ +struct splay_tree_s GTY(()) +{ + /* The root of the tree. */ + splay_tree_node GTY ((use_params)) root; + + /* The comparision function. */ + splay_tree_compare_fn comp; + + /* The deallocate-key function. NULL if no cleanup is necessary. */ + splay_tree_delete_key_fn delete_key; + + /* The deallocate-value function. NULL if no cleanup is necessary. */ + splay_tree_delete_value_fn delete_value; + + /* Allocate/free functions, and a data pointer to pass to them. */ + splay_tree_allocate_fn allocate; + splay_tree_deallocate_fn deallocate; + void * GTY((skip)) allocate_data; + +}; +typedef struct splay_tree_s *splay_tree; + +extern splay_tree splay_tree_new (splay_tree_compare_fn, + splay_tree_delete_key_fn, + splay_tree_delete_value_fn); +extern splay_tree splay_tree_new_with_allocator (splay_tree_compare_fn, + splay_tree_delete_key_fn, + splay_tree_delete_value_fn, + splay_tree_allocate_fn, + splay_tree_deallocate_fn, + void *); +extern void splay_tree_delete (splay_tree); +extern splay_tree_node splay_tree_insert (splay_tree, + splay_tree_key, + splay_tree_value); +extern void splay_tree_remove (splay_tree, splay_tree_key); +extern splay_tree_node splay_tree_lookup (splay_tree, splay_tree_key); +extern splay_tree_node splay_tree_predecessor (splay_tree, splay_tree_key); +extern splay_tree_node splay_tree_successor (splay_tree, splay_tree_key); +extern splay_tree_node splay_tree_max (splay_tree); +extern splay_tree_node splay_tree_min (splay_tree); +extern int splay_tree_foreach (splay_tree, splay_tree_foreach_fn, void*); +extern int splay_tree_compare_ints (splay_tree_key, splay_tree_key); +extern int splay_tree_compare_pointers (splay_tree_key, splay_tree_key); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _SPLAY_TREE_H */ + diff --git a/minix/llvm/include/magic_structs.h b/minix/llvm/include/magic_structs.h new file mode 100644 index 000000000..6634fb927 --- /dev/null +++ b/minix/llvm/include/magic_structs.h @@ -0,0 +1,312 @@ +#ifndef _MAGIC_STRUCTS_H +#define _MAGIC_STRUCTS_H + +#include +#include +#include +#include + +/* Magic state type struct. */ +struct _magic_type { + _magic_id_t id; + char *name; + char **names; + unsigned num_names; + char *type_str; + unsigned size; + unsigned num_child_types; + struct _magic_type **contained_types; + struct _magic_type **compatible_types; + char **member_names; + unsigned *member_offsets; + void *value_set; + unsigned type_id; + int flags; + unsigned bit_width; + void *ext; +}; + +/* Magic state entry struct. */ +struct _magic_sentry { + _magic_id_t id; + char *name; + struct _magic_type *type; + int flags; + void *address; + void *shadow_address; +}; + +/* Magic state entry list struct. */ +struct _magic_sentry_list { + struct _magic_sentry *sentry; + struct _magic_sentry_list *next; +}; + +/* Magic state entry hash struct. */ +#define MAGIC_SENTRY_NAME_MAX_KEY_LEN 512 +struct _magic_sentry_hash { + struct _magic_sentry_list *sentry_list; + char key[MAGIC_SENTRY_NAME_MAX_KEY_LEN]; + UT_hash_handle hh; +}; + +/* Magic state function struct. */ +struct _magic_function { + _magic_id_t id; + char *name; + struct _magic_type *type; + int flags; + void *address; +}; + +/* Magic state function hash struct. */ +struct _magic_function_hash { + struct _magic_function *function; + void *key; + UT_hash_handle hh; +}; + +/* Magic dynamic function struct. */ +struct _magic_dfunction { + unsigned long magic_number; + char *parent_name; + struct _magic_function function; + struct _magic_dfunction *prev; + struct _magic_dfunction *next; +}; + +/* Magic dynamic state index struct. */ +struct _magic_dsindex { + struct _magic_type *type; + char *name; + char *parent_name; + int flags; +}; + +/* Magic dynamic state entry struct. */ +#define MAGIC_DSENTRY_ALLOW_PREV 0 +/* + * The name of an externally allocated dsentry will be: + * strlen("MAGIC_EXT_ALLOC_NAME") + strlen("MAGIC_ALLOC_NAME_SEP") + + * strlen(0xffffffff) + strlen("MAGIC_ALLOC_NAME_SUFFIX") + 1 = + * 4 + 1 + 10 + 1 + 1 = 17 + */ +#define MAGIC_DSENTRY_EXT_NAME_BUFF_SIZE 17 + +struct _magic_dsentry { + unsigned long magic_number; + char *parent_name; + char name_ext_buff[MAGIC_DSENTRY_EXT_NAME_BUFF_SIZE]; + struct _magic_sentry sentry; + struct _magic_type type; + struct _magic_type *type_array[1]; +#if MAGIC_DSENTRY_ALLOW_PREV + struct _magic_dsentry *prev; +#endif + struct _magic_dsentry *next; + struct _magic_dsentry *next_mpool; + struct _magic_dsentry *next_mblock; + /* + * The following 2 fields are only set if the dsentry + * is part of a super object. + * See llvm/shared/magic/libst/include/heap.h for more details. + */ +#ifndef __MINIX + struct _magic_dsentry *next_sobject; + void *sobject_base_addr; +#endif + void *ext; + unsigned long magic_state; + union __alloc_flags { + struct { + int flags; + int prot; + } mmap_call; +#define mmap_flags mmap_call.flags +#define mmap_prot mmap_call.prot + struct { + int flags; + int shmid; + } shmat_call; +#define shmat_flags shmat_call.flags +#define shmat_shmid shmat_call.shmid + } alloc_flags; +#define alloc_mmap_flags alloc_flags.mmap_call.flags +#define alloc_mmap_prot alloc_flags.mmap_call.prot +#define alloc_shmat_flags alloc_flags.shmat_call.flags +#define alloc_shmat_shmid alloc_flags.shmat_call.shmid + _magic_id_t site_id; /* Identifier of the call at a callsite. */ +}; + +/* Magic out-of-band dynamic state entry struct. */ +#define MAGIC_MAX_OBDSENTRIES 32 +#define MAGIC_MAX_OBDSENTRY_NAME_LEN 32 +#define MAGIC_MAX_OBDSENTRY_PARENT_NAME_LEN 32 +struct _magic_obdsentry { + char name[MAGIC_MAX_OBDSENTRY_NAME_LEN]; + char parent_name[MAGIC_MAX_OBDSENTRY_PARENT_NAME_LEN]; + struct _magic_dsentry dsentry; +}; +EXTERN struct _magic_obdsentry _magic_obdsentries[MAGIC_MAX_OBDSENTRIES]; + +/* Magic memory pool state struct. */ +#define MAGIC_MAX_MEMPOOLS 1024 +#define MAGIC_MAX_MEMPOOL_NAME_LEN 32 +#define MAGIC_MEMPOOL_NAME_PREFIX "_magic_mempool_" +EXTERN char *const MAGIC_MEMPOOL_NAME_UNKNOWN; +EXTERN char *const MAGIC_MEMPOOL_NAME_DETACHED; + +struct _magic_mpdesc { + int is_alive; + char name[MAGIC_MAX_MEMPOOL_NAME_LEN]; + /* pointer to the pool object */ + void *addr; +#if MAGIC_MEM_USAGE_OUTPUT_CTL + unsigned long dtype_id; +#endif +}; +EXTERN struct _magic_mpdesc _magic_mpdescs[MAGIC_MAX_MEMPOOLS]; + +/* Magic state element. */ +struct _magic_selement_s { + struct _magic_dsentry dsentry_buff; + struct _magic_sentry *sentry; + const struct _magic_type *parent_type; + void *parent_address; + int child_num; + const struct _magic_type *type; + void *address; + int depth; + int num; + void *cb_args; +}; +typedef struct _magic_selement_s _magic_selement_t; + +/* Magic external library descriptor. */ +struct _magic_libdesc { + const char *name; + void *text_range[2]; + void *data_range[2]; + void *alloc_address; + size_t alloc_size; +}; + +/* Magic SO library descriptor. */ +struct _magic_sodesc { + struct _magic_libdesc lib; + struct _magic_sodesc *prev; + struct _magic_sodesc *next; +}; + +/* Magic DSO library descriptor. */ +struct _magic_dsodesc { + struct _magic_libdesc lib; + void *handle; + int ref_count; + struct _magic_dsodesc *prev; + struct _magic_dsodesc *next; +}; + +/* Magic vars. */ +struct _magic_vars_t { + + /* Magic Address Space Randomization (ASRPass) */ + int asr_seed; + int asr_heap_map_do_permutate; + int asr_heap_max_offset; + int asr_heap_max_padding; + int asr_map_max_offset_pages; + int asr_map_max_padding_pages; + + /* Magic type array. */ + struct _magic_type *types; + int types_num; + _magic_id_t types_next_id; + + /* Magic function array. */ + struct _magic_function *functions; + int functions_num; + _magic_id_t functions_next_id; + + /* Magic state entry array. */ + struct _magic_sentry *sentries; + int sentries_num; + int sentries_str_num; + _magic_id_t sentries_next_id; + + /* Magic dynamic state index array. */ + struct _magic_dsindex *dsindexes; + int dsindexes_num; + + /* Magic dynamic state entry list. */ + struct _magic_dsentry *first_dsentry; + unsigned long num_dead_dsentries; + unsigned long size_dead_dsentries; + + /* Magic memory pool dynamic state entry list. */ + struct _magic_dsentry *first_mempool_dsentry; + + /* Magic dynamic function list. */ + struct _magic_dfunction *first_dfunction; + struct _magic_dfunction *last_dfunction; + int dfunctions_num; + + /* Magic SO library descriptor list. */ + struct _magic_sodesc *first_sodesc; + struct _magic_sodesc *last_sodesc; + int sodescs_num; + + /* Magic DSO library descriptor list. */ + struct _magic_dsodesc *first_dsodesc; + struct _magic_dsodesc *last_dsodesc; + int dsodescs_num; + + /* Magic stack-related variables. */ + struct _magic_dsentry *first_stack_dsentry; + struct _magic_dsentry *last_stack_dsentry; + + /* Magic memory ranges */ + void *null_range[2]; + void *data_range[2]; + void *heap_range[2]; + void *map_range[2]; + void *shm_range[2]; + void *stack_range[2]; + void *text_range[2]; + + void *sentry_range[2]; + void *function_range[2]; + void *dfunction_range[2]; + + void *heap_start; + void *heap_end; + int update_dsentry_ranges; + int update_dfunction_ranges; + + /* Range lookup index */ + void *sentry_rl_buff; + size_t sentry_rl_buff_offset; + size_t sentry_rl_buff_size; + void *sentry_rl_index; + + /* Sentry hash */ + void *sentry_hash_buff; + size_t sentry_hash_buff_offset; + size_t sentry_hash_buff_size; + void *sentry_hash_head; + + /* Function hash */ + void *function_hash_buff; + size_t function_hash_buff_offset; + size_t function_hash_buff_size; + void *function_hash_head; + + /* + * Don't call malloc() in magic_malloc_positioned(). + * Used in ST after RAW COPY. + */ + int fake_malloc; +}; + + +#endif /* _MAGIC_STRUCTS_H */ diff --git a/minix/llvm/include/st/callback.h b/minix/llvm/include/st/callback.h new file mode 100644 index 000000000..9287508cc --- /dev/null +++ b/minix/llvm/include/st/callback.h @@ -0,0 +1,127 @@ +#ifndef ST_CALLBACK_H +#define ST_CALLBACK_H + +#include + +#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 + +DEFINE_DECL_CALLBACK(void *, pages_allocate, (st_init_info_t *info, uint32_t *phys, int num_pages)); +DEFINE_DECL_CALLBACK(void, pages_free, (st_init_info_t *info, st_alloc_pages *current_page)); +DEFINE_DECL_CALLBACK(int, state_cleanup, (void)); +typedef magic_sentry_analyze_cb_t st_cb_state_checking_t; +PUBLIC void st_setcb_state_checking(st_cb_state_checking_t cb); +DEFINE_DECL_CALLBACK(void, selement_map, (_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)); +DEFINE_DECL_CALLBACK_CUSTOM(int, selement_transfer, (_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info), (CALLBACK_TYPENAME(selement_transfer) cb, int flags)); + +/* Struct for holding state transfer callback functions. */ +struct st_cbs_t { + st_cb_pages_allocate_t st_cb_pages_allocate; + st_cb_pages_free_t st_cb_pages_free; + st_cb_state_cleanup_t st_cb_state_cleanup; + st_cb_state_checking_t st_cb_state_checking; + st_cb_selement_map_t st_cb_selement_map; + st_cb_selement_transfer_t st_cb_selement_transfer[NUM_CB_ARRAYS][MAX_NUM_CBS]; +}; + +/* Predefined callback implementations. */ +PUBLIC void *st_cb_pages_allocate(st_init_info_t *info, uint32_t *phys, int num_pages); +PUBLIC void st_cb_pages_free(st_init_info_t *info, st_alloc_pages *current_page); +PUBLIC int st_cb_state_cleanup_null(void); +PUBLIC int st_cb_state_checking_null(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args); +PUBLIC int st_cb_state_checking_print(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args); +PUBLIC int st_cb_state_checking_panic(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args); + +PUBLIC int st_cb_transfer_sentry_default(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC int st_cb_transfer_typename_default(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC int st_cb_transfer_walkable(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC int st_cb_transfer_ptr(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC int st_cb_transfer_identity(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC int st_cb_transfer_cond_identity(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC int st_cb_transfer_nonptr(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC int st_cb_transfer_struct(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC int st_cb_transfer_selement_base(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC int st_cb_transfer_selement_generic(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); + +PUBLIC void st_cb_map_from_parent_array_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); +PUBLIC void st_cb_map_child_array_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); +PUBLIC void st_cb_map_from_parent_union_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); +PUBLIC void st_cb_map_child_union_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); +PUBLIC void st_cb_map_from_parent_struct_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); +PUBLIC void st_cb_map_child_struct_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); +PUBLIC void st_cb_map_child_primitive_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); +PUBLIC void st_cb_map_child_ptr_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); +PUBLIC void st_cb_map_from_parent_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); +PUBLIC void st_cb_map_child_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); +PUBLIC void st_cb_map_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); + +/* Macros for callbacks not defined statically. */ +#define ST_CB_SELEMENT_TRANSFER_EMPTY {{0}} + +/* Macros for predefined callback implementations. */ +#define ST_CB_PAGES_ALLOCATE_DEFAULT st_cb_pages_allocate +#define ST_CB_PAGES_FREE_DEFAULT st_cb_pages_free +#define ST_CB_STATE_CLEANUP_DEFAULT st_cb_state_cleanup_null +#define ST_CB_STATE_CHECKING_DEFAULT st_cb_state_checking_print +#define ST_CB_SELEMENT_MAP_DEFAULT st_cb_map_selement_generic + +#define ST_CB_PRINT st_cb_print + +#define ST_TYPE_NAME_KEY(TYPE) ((char *) (TYPE)->ext) + +#define ST_TYPE_NAME_MATCH(REGISTERED_TYPE_NAME_KEY, KEY) \ + (REGISTERED_TYPE_NAME_KEY == KEY) +#define ST_TYPE_NAME_MATCH_ANY(REGISTERED_TYPE_NAME_KEYS, KEY) \ + st_type_name_match_any(REGISTERED_TYPE_NAME_KEYS, KEY) +#define ST_SENTRY_NAME_MATCH(SENTRY_WILDCARD_NAME, NAME) \ + (!st_strcmp_wildcard(SENTRY_WILDCARD_NAME, NAME)) +#define ST_SENTRY_NAME_MATCH_ANY(SENTRY_WILDCARD_NAMES, NAME) \ + st_sentry_name_match_any(SENTRY_WILDCARD_NAMES, NAME) +#define ST_DSENTRY_PARENT_NAME_MATCH(DSENTRY_WILDCARD_PARENT_NAME, PARENT_NAME)\ + (!st_strcmp_wildcard(DSENTRY_WILDCARD_PARENT_NAME, PARENT_NAME)) +#define ST_DSENTRY_PARENT_NAME_MATCH_ANY(DSENTRY_WILDCARD_PARENT_NAMES, \ + PARENT_NAME) \ + st_dsentry_parent_name_match_any(DSENTRY_WILDCARD_PARENT_NAMES, PARENT_NAME) + +#define ST_CB_TYPE_TYPENAME 1 +#define ST_CB_TYPE_SENTRY 2 +#define ST_CB_TYPE_SELEMENT 4 +#define ST_CB_NOT_PROCESSED 1000 + +#define ST_CB_CHECK_ONLY 0x01 +#define ST_CB_PRINT_DBG 0x02 +#define ST_CB_PRINT_ERR 0x04 +#define ST_CB_FORCE_IXFER 0x08 +#define ST_CB_DEFAULT_FLAGS (ST_CB_PRINT_DBG|ST_CB_PRINT_ERR) +#define ST_CB_FLAG(F) (cb_info->st_cb_flags & F) + +#define ST_CB_DBG ST_CB_PRINT_DBG +#define ST_CB_ERR ST_CB_PRINT_ERR +#define ST_CB_PRINT_LEVEL(L) ST_CB_FLAG(L) +#define ST_CB_LEVEL_TO_STR(L) \ + (L == ST_CB_DBG ? "DEBUG" : \ + L == ST_CB_ERR ? "ERROR" : "???") + +#endif /* ST_CALLBACK_H */ diff --git a/minix/llvm/include/st/cb_template.h b/minix/llvm/include/st/cb_template.h new file mode 100644 index 000000000..bf3954bbb --- /dev/null +++ b/minix/llvm/include/st/cb_template.h @@ -0,0 +1,28 @@ +#undef xglue +#undef glue +#undef CALLBACK_TYPENAME +#undef CALLBACK_SETTERNAME +#undef DEFINE_CALLBACK +#undef DECLARE_CALLBACK + +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) + +#ifdef CALLBACK_FAMILY +#define CALLBACK_TYPENAME(name) glue(glue(glue(glue(glue(CALLBACK_PREFIX, _cb_), CALLBACK_FAMILY), _), name), _t) +#define CALLBACK_SETTERNAME(name) glue(glue(glue(glue(CALLBACK_PREFIX, _setcb_), CALLBACK_FAMILY), _), name) +#else +#define CALLBACK_TYPENAME(name) glue(glue(glue(CALLBACK_PREFIX, _cb_), name), _t) +#define CALLBACK_SETTERNAME(name) glue(glue(CALLBACK_PREFIX, _setcb_), name) +#endif + +#define DECLARE_CALLBACK(ret_type, name, args) \ +typedef ret_type(*CALLBACK_TYPENAME(name))args + +#define DEFINE_DECL_CALLBACK(ret_type, name, args) \ +DECLARE_CALLBACK(ret_type, name, args); \ +void CALLBACK_SETTERNAME(name)(CALLBACK_TYPENAME(name) cb) + +#define DEFINE_DECL_CALLBACK_CUSTOM(ret_type, name, args, setter_args) \ +DECLARE_CALLBACK(ret_type, name, args); \ +void CALLBACK_SETTERNAME(name)setter_args diff --git a/minix/llvm/include/st/metadata_transfer.h b/minix/llvm/include/st/metadata_transfer.h new file mode 100644 index 000000000..371731d2f --- /dev/null +++ b/minix/llvm/include/st/metadata_transfer.h @@ -0,0 +1,60 @@ +#ifndef METADATA_TRANSFER_H +#define METADATA_TRANSFER_H + +#include + +/* Metadata transfer and adjustment functions */ +PRIVATE int transfer_metadata_functions(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, + struct _magic_vars_t *remote_magic_vars, + st_counterparts_t *counterparts); +PRIVATE int transfer_metadata_dfunctions(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, + struct _magic_vars_t *remote_magic_vars, + st_counterparts_t *counterparts); +PRIVATE int transfer_metadata_type_members(st_init_info_t *info, + struct _magic_type *type, struct _magic_vars_t *cached_magic_vars, + struct _magic_vars_t *remote_magic_vars); +PRIVATE int transfer_metadata_sentries(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, + struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts, + int *max_buff_sz); +PRIVATE int transfer_metadata_sentry_members(st_init_info_t *info, + struct _magic_sentry *sentry); + +PRIVATE int pair_metadata_types(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, + st_counterparts_t *counterparts, int allow_unpaired_types); +PRIVATE int pair_metadata_functions(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts); +PRIVATE int pair_metadata_sentries(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts); +#if !ST_ASSUME_RAW_COPY_BEFORE_TRANSFER +PRIVATE int allocate_pair_metadata_dsentries(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts); +#else +PRIVATE int allocate_pair_metadata_dsentries_from_raw_copy(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts); +#endif + +/* metadata transfer helper functions */ +PRIVATE int md_transfer_str(st_init_info_t *info, char **str_pt); +#define MD_TRANSFER_STR(INFO, STR_PT) \ + do { \ + if (md_transfer_str(INFO, STR_PT)) { \ + printf("%s, line %d. md_transfer_str(): ERROR transferring.\n", \ + __FILE__, __LINE__); \ + return EGENERIC; \ + } \ + } while(0) +PRIVATE int md_transfer(st_init_info_t *info, void *from, void **to, int len); +#define MD_TRANSFER(INFO, FROM, TO, LEN) \ + do { \ + if (md_transfer(INFO, FROM, TO, LEN)) { \ + printf("%s, line %d. md_transfer(): ERROR transferring.\n", \ + __FILE__, __LINE__); \ + return EGENERIC; \ + } \ + } while(0) + +#endif /* METADATA_TRANSFER_H */ diff --git a/minix/llvm/include/st/os_callback.h b/minix/llvm/include/st/os_callback.h new file mode 100644 index 000000000..590a22475 --- /dev/null +++ b/minix/llvm/include/st/os_callback.h @@ -0,0 +1,39 @@ +#ifndef ST_OS_CALLBACK_H +#define ST_OS_CALLBACK_H + +#include + +/* Callback type definitions and call registration helpers. */ + +#define CALLBACK_PREFIX st +#define CALLBACK_FAMILY os +#include + +DEFINE_DECL_CALLBACK(void, panic, (const char *fmt, ...)); +DEFINE_DECL_CALLBACK(int, old_state_table_lookup, (void *state_info_opaque, void *vars)); +DEFINE_DECL_CALLBACK(int, copy_state_region, (void *state_info_opaque, uint32_t address, size_t size, uint32_t dst_address)); +DEFINE_DECL_CALLBACK(void *, alloc_contig, (size_t len, int flags, uint32_t *phys)); +DEFINE_DECL_CALLBACK(int, free_contig, (void *ptr, size_t length)); +DEFINE_DECL_CALLBACK(char *, debug_header, (void)); + +/* Default callback values. */ +#define ST_CB_OS_PANIC_EMPTY NULL +#define ST_CB_OS_OLD_STATE_TABLE_LOOKUP_EMPTY NULL +#define ST_CB_OS_COPY_STATE_REGION_EMPTY NULL +#define ST_CB_OS_ALLOC_CONTIG_EMPTY NULL +#define ST_CB_OS_FREE_CONTIG_EMPTY NULL +#define ST_CB_OS_DEBUG_HEADER_EMPTY NULL + +struct st_cbs_os_t { + CALLBACK_TYPENAME(panic) panic; + CALLBACK_TYPENAME(old_state_table_lookup) old_state_table_lookup; + CALLBACK_TYPENAME(copy_state_region) copy_state_region; + CALLBACK_TYPENAME(alloc_contig) alloc_contig; + CALLBACK_TYPENAME(free_contig) free_contig; + CALLBACK_TYPENAME(debug_header) debug_header; +}; + +/* General callback registration helper. */ +PUBLIC void st_setcb_os_all(struct st_cbs_os_t *cbs); + +#endif /* ST_OS_CALLBACK_H */ diff --git a/minix/llvm/include/st/private.h b/minix/llvm/include/st/private.h new file mode 100644 index 000000000..e8d118884 --- /dev/null +++ b/minix/llvm/include/st/private.h @@ -0,0 +1,34 @@ +#ifndef ST_PRIVATE_H +#define ST_PRIVATE_H + + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* Data transfer and adjustment functions */ +#if !ST_ASSUME_RAW_COPY_BEFORE_TRANSFER +PRIVATE int deallocate_nonxferred_dsentries(struct _magic_dsentry *first_dsentry, st_counterparts_t *counterparts); +#endif +PRIVATE void deallocate_local_dsentry(struct _magic_dsentry *local_dsentry); +PRIVATE int allocate_local_dsentry(st_init_info_t *info, struct _magic_dsindex *local_dsindex, int num_elements, int is_type_mismatch, const union __alloc_flags *p_alloc_flags, struct _magic_dsentry** local_dsentry_ptr, struct _magic_dsentry *cached_dsentry, void *ptr); + +PRIVATE int check_unpaired_sentry(st_init_info_t *info, struct _magic_sentry* cached_sentry); +PRIVATE int transfer_data_sentry(st_init_info_t *info, struct _magic_sentry* cached_sentry); +PRIVATE int transfer_data_selement(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, void *cb_args); +PRIVATE int lookup_trg_info(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info, + _magic_selement_t *cached_trg_selement, _magic_selement_t *local_trg_selement); +PRIVATE INLINE void st_set_transfer_status(int status_flags, int status_op, + struct _magic_sentry *cached_sentry, struct _magic_function *cached_function); +PRIVATE INLINE void st_map_selement(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping); + +/* Buffer allocation */ +PRIVATE void *persistent_mmap(__MA_ARGS__ st_init_info_t *info, void *start, size_t length, int prot, int flags, int fd, off_t offset, struct _magic_dsentry *dsentry); + +#endif /* ST_PRIVATE_H */ diff --git a/minix/llvm/include/st/special.h b/minix/llvm/include/st/special.h new file mode 100644 index 000000000..7c2a85330 --- /dev/null +++ b/minix/llvm/include/st/special.h @@ -0,0 +1,10 @@ +#ifndef ST_SPECIAL_H +#define ST_SPECIAL_H + +/* Public functions for special types and regions. */ +PUBLIC void st_register_typename_key(char *key); +PUBLIC void st_register_typename_keys(char **keys); +PUBLIC int st_add_special_mmapped_region(void *address, size_t size, char* name); +PUBLIC int st_del_special_mmapped_region_by_addr(void *address); + +#endif /* ST_SPECIAL_H */ diff --git a/minix/llvm/include/st/state_transfer.h b/minix/llvm/include/st/state_transfer.h new file mode 100644 index 000000000..4ff023caf --- /dev/null +++ b/minix/llvm/include/st/state_transfer.h @@ -0,0 +1,362 @@ +#ifndef ST_STATE_TRANSFER_H +#define ST_STATE_TRANSFER_H + + +#include +#include +#include +#include +#include +#include + +#ifdef __MINIX +#include +#include +#endif + +/* + * Used for debugging: Iterate the type transformations X times. + */ +#define MAGIC_ST_TYPE_TRANS_ITERATIONS 1 + +#include +#include + +#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 + +/* struct for holding a mapping between pointers */ +typedef struct { + void *counterpart; +} st_ptr_mapping; + +/* struct for holding arrays of local counterparts to cached variables */ +typedef struct { + st_ptr_mapping *functions; + int functions_size; + st_ptr_mapping *types; + st_ptr_mapping *ptr_types; + int types_size; + st_ptr_mapping *sentries; + st_ptr_mapping *sentries_data; + int sentries_size; +} st_counterparts_t; + +#define ST_STATE_CHECKING_DEFAULT_MAX_CYCLES LONG_MAX +#define ST_STATE_CHECKING_DEFAULT_MAX_VIOLATIONS 50 + +#define ST_SEL_ANALYZE_FLAGS (MAGIC_SEL_ANALYZE_ALL & (~MAGIC_SEL_ANALYZE_OUT_OF_BAND)) + +#define ST_MAX_COMPATIBLE_TYPES 32 + +/* Fields of _magic_vars_t that need to be zeroed out after transferring. */ +#define ST_MAGIC_VARS_PTR_CLEAR_LIST \ + __X(first_sodesc), __X(last_sodesc), \ + __X(first_dsodesc), __X(last_dsodesc), \ + __X(sentry_rl_buff), __X(sentry_rl_index), \ + __X(sentry_hash_buff), __X(sentry_hash_head), \ + __X(function_hash_buff), __X(function_hash_head) + +/* Public utility functions. */ +PUBLIC int st_strcmp_wildcard(char *with_wildcard, char *without_wildcard); +PUBLIC void st_cb_print(int level, char *msg, _magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC void st_map_str_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr); +PUBLIC void st_map_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr); +PUBLIC void st_lookup_sentry_pair(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr); +PUBLIC void st_add_sentry_pair(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry); +PUBLIC int st_add_sentry_pair_alloc_by_dsindex(st_init_info_t *info, struct _magic_sentry *cached_sentry, struct _magic_dsindex *local_dsindex, int num_elements, const union __alloc_flags *p_alloc_flags); +PUBLIC void st_map_functions(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr); +PUBLIC void st_lookup_function_pair(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr); +PUBLIC void st_add_function_pair(struct _magic_function *cached_function, struct _magic_function *local_function); +PUBLIC int st_sentry_equals(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry); +PUBLIC int st_function_equals(struct _magic_function *cached_function, struct _magic_function *local_function); +PUBLIC void st_print_sentry_diff(st_init_info_t *info, struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry, int raw_diff, int print_changed); +PUBLIC void st_print_function_diff(st_init_info_t *info, struct _magic_function *cached_function, struct _magic_function *local_function, int raw_diff, int print_changed); +PUBLIC void st_cb_selement_type_cast(const struct _magic_type* new_selement_type, const struct _magic_type* new_local_selement_type, _magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); +PUBLIC void st_map_local_selement_from_child_num(_magic_selement_t *local_selement, struct st_cb_info *cb_info, int child_num); + +/* Stack refs save/restore. */ +PUBLIC void st_stack_refs_save_restore(char *stack_buff, int is_save); + +#define st_stack_refs_save(B) st_stack_refs_save_restore(B,1) +#define st_stack_refs_restore(B) st_stack_refs_save_restore(B,0) + +#define ST_STACK_REFS_BUFF_SIZE (sizeof(struct st_stack_refs_buff)) + +/* + * The stack pointers to the environment and arguments differ from MINIX + * to Linux. + */ +#if defined(__MINIX) +#define ST_STACK_REFS_INT_NUM 3 +#define ST_STACK_REFS_INT_LIST \ + __X(environ), __X(env_argv), __X(env_argc) +#define ST_STACK_REFS_CUSTOM_NUM 0 +#define ST_STACK_REFS_CUSTOM_LIST + +#else +/* + * TODO: Complete the list of Linux stack pointer aliases. + */ +#define ST_STACK_REFS_INT_NUM 3 +#define ST_STACK_REFS_INT_LIST __X(_environ), __X(__progname), \ + __X(__progname_full) + +#ifndef __USE_GNU +extern char *program_invocation_name, *program_invocation_short_name; +extern char **environ; +#endif +#define ST_STACK_REFS_CUSTOM_NUM 4 +#define ST_STACK_REFS_CUSTOM_LIST __X(environ), __X(__environ), \ + __X(program_invocation_name), __X(program_invocation_short_name) + +#endif + +#define ST_STACK_REFS_NUM (ST_STACK_REFS_INT_NUM + ST_STACK_REFS_CUSTOM_NUM) + +struct st_stack_refs_buff { + struct _magic_dsentry *first_stack_dsentry; + struct _magic_dsentry *last_stack_dsentry; + struct _magic_obdsentry first_stack_obdsentry_buff; + void* stack_range[2]; + int stack_int_refs[ST_STACK_REFS_NUM]; +}; + +/* Public functions for metadata transfer. */ +PUBLIC int st_transfer_metadata_types(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, + struct _magic_vars_t *remote_magic_vars, + st_counterparts_t *counterparts); +PUBLIC int st_transfer_metadata_dsentries(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, + struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts, + int *max_buff_sz, int *dsentries_num); + +/* Public functions for state transfer. */ +PUBLIC int st_state_transfer(st_init_info_t *info); +PUBLIC void st_msync_all_shm_dsentries(void); + +PUBLIC int st_init(st_init_info_t *info); +PUBLIC void st_set_status_defaults(st_init_info_t *info); +PUBLIC int st_data_transfer(st_init_info_t *info); +PUBLIC void st_cleanup(st_init_info_t *info); + +PUBLIC void st_set_unpaired_types_ratios(float unpaired_types_ratio, float unpaired_struct_types_ratio); + +PUBLIC struct _magic_sentry* st_cached_to_remote_sentry(st_init_info_t *info, struct _magic_sentry *cached_sentry); + +PUBLIC void st_print_sentries_diff(st_init_info_t *info, int raw_diff, int print_changed); +PUBLIC void st_print_dsentries_diff(st_init_info_t *info, int raw_diff, int print_changed); +PUBLIC void st_print_functions_diff(st_init_info_t *info, int raw_diff, int print_changed); +PUBLIC void st_print_state_diff(st_init_info_t *info, int raw_diff, int print_changed); + +PUBLIC void st_set_status_by_state_flags(int status_flags, int status_op, int match_state_flags, int skip_state_flags); +PUBLIC int st_set_status_by_function_ids(int status_flags, int status_op, unsigned long *ids); +PUBLIC int st_set_status_by_sentry_ids(int status_flags, int status_op, unsigned long *ids); +PUBLIC int st_set_status_by_names(int status_flags, int status_op, char **parent_names, char **names, _magic_id_t *dsentry_site_ids); +PUBLIC int st_set_status_by_local_addrs(int status_flags, int status_op, void **addrs); +PUBLIC void st_set_status_by_sentry(int status_flags, int status_op, void *cached_sentry); +PUBLIC void st_set_status_by_function(int status_flags, int status_op, void *cached_function); +PUBLIC int st_set_status_by_function_id(int status_flags, int status_op, unsigned long id); +PUBLIC int st_set_status_by_sentry_id(int status_flags, int status_op, unsigned long id); +PUBLIC int st_set_status_by_name(int status_flags, int status_op, char *parent_name, char *name, _magic_id_t dsentry_site_id); +PUBLIC int st_set_status_by_local_addr(int status_flags, int status_op, void *addr); + +PUBLIC int st_pair_by_function_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op); +PUBLIC int st_pair_by_sentry_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op); +PUBLIC int st_pair_by_names(char **cached_parent_names, char **cached_names, char **local_parent_names, char **local_names, _magic_id_t *dsentry_site_ids, int status_flags, int status_op); +PUBLIC void st_pair_by_sentry(void *cached_sentry, void *local_sentry, int status_flags, int status_op); +PUBLIC void st_pair_by_function(void *cached_function, void* local_function, int status_flags, int status_op); +PUBLIC int st_pair_alloc_by_dsindex(st_init_info_t *info, void *cached_sentry, void *local_dsindex, int num_elements, const union __alloc_flags *p_alloc_flags, int status_flags, int status_op); +PUBLIC int st_pair_by_function_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op); +PUBLIC int st_pair_by_sentry_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op); +PUBLIC int st_pair_by_name(char *cached_parent_name, char *cached_name, char *local_parent_name, char *local_name, _magic_id_t dsentry_site_id, int status_flags, int status_op); +PUBLIC int st_pair_by_alloc_name(st_init_info_t *info, char *cached_parent_name, char *cached_name, _magic_id_t cached_dsentry_site_id, char *local_parent_name, char *local_name, _magic_id_t local_dsentry_site_id, int num_elements, const union __alloc_flags *p_alloc_flags, int status_flags, int status_op); +PUBLIC int st_pair_by_alloc_name_policies(st_init_info_t *info, char *cached_parent_name, char *cached_name, _magic_id_t cached_dsentry_site_id, char *local_parent_name, char *local_name, _magic_id_t local_dsentry_site_id, int num_elements, const union __alloc_flags *p_alloc_flags, int alloc_policies, int status_flags, int status_op); + +/* Public functions for state checking. */ +PUBLIC int st_do_state_cleanup(void); +PUBLIC int st_do_state_checking(void); +PUBLIC int st_state_checking_before_receive_is_enabled(void); +PUBLIC int st_state_checking_before_receive_set_enabled(int enabled, int max_cycles, int max_violations); + +/* State transfer status flags and operations. */ +#define ST_NEEDS_TRANSFER 0x01 +#define ST_TRANSFER_DONE 0x02 +#define ST_ON_PTRXFER_CASCADE 0x04 +#define ST_ON_PTRXFER_SET_NULL 0x08 +#define ST_ON_PTRXFER_SET_DEFAULT 0x10 +#define ST_ON_PTRXFER_SKIP 0x20 + +#define ST_OP_NONE 0 +#define ST_OP_ADD 1 +#define ST_OP_DEL 2 +#define ST_OP_SET 3 +#define ST_OP_CLEAR 4 + +/* State transfer policies. */ +#define ST_DEFAULT_TRANSFER_NONE 0x00000001 +#define ST_DEFAULT_ALLOC_CASCADE_XFER 0x00000002 +#define ST_DEFAULT_SKIP_STACK 0x00000004 +#define ST_DEFAULT_SKIP_LIB_STATE 0x00000008 +#define ST_TRANSFER_DIRTY_ONLY 0x00000010 +#define ST_IXFER_UNCAUGHT_UNIONS 0x00000020 +#define ST_REPORT_UNCAUGHT_UNIONS 0x00000040 +#define ST_REPORT_NONXFERRED_ALLOCS 0x00000080 +#define ST_REPORT_NONXFERRED_UNPAIRED_ALLOCS 0x00000100 +#define ST_REPORT_UNPAIRED_SENTRIES 0x00000200 +#define ST_REPORT_UNPAIRED_DSENTRIES 0x00000400 +#define ST_REPORT_UNPAIRED_STRINGS 0x00000800 +#define ST_REPORT_UNPAIRED_SELEMENTS 0x00001000 +#define ST_MAP_NAMED_STRINGS_BY_NAME 0x00002000 +#define ST_MAP_NAMED_STRINGS_BY_CONTENT 0x00004000 +#define ST_MAP_STRINGS_BY_CONTENT 0x00008000 +#define ST_ON_ALLOC_UNPAIR_ERROR 0x00010000 +#define ST_ON_ALLOC_UNPAIR_DEALLOCATE 0x00020000 +#define ST_ON_ALLOC_UNPAIR_IGNORE 0x00040000 +#define ST_DEFAULT_MAP_GUARD_PTRS_TO_ARRAY_END 0x00080000 +#define ST_DEFAULT_MAP_GUARD_PTRS_TO_STR_END 0x00100000 +#define ST_REPORT_PRECISION_LOSS 0x00200000 +#define ST_REPORT_SIGN_CHANGE 0x00400000 +#define ST_REPORT_SMALLER_ARRAYS 0x00800000 +#define ST_REPORT_LARGER_ARRAYS 0x01000000 +#define ST_REPORT_SMALLER_STRINGS 0x02000000 +#define ST_REPORT_LARGER_STRINGS 0x04000000 + +#define ST_REPORT_UNPAIRED_ALL \ + (ST_REPORT_UNPAIRED_SENTRIES | ST_REPORT_UNPAIRED_DSENTRIES | \ + ST_REPORT_UNPAIRED_STRINGS | ST_REPORT_UNPAIRED_SELEMENTS) +#define ST_MAP_STRINGS_DEFAULT \ + (ST_MAP_NAMED_STRINGS_BY_NAME | ST_MAP_STRINGS_BY_CONTENT) +#define ST_ON_ALLOC_UNPAIR_DEFAULT (ST_ON_ALLOC_UNPAIR_ERROR) +#define ST_ON_ALLOC_UNPAIR_MASK \ + (ST_ON_ALLOC_UNPAIR_ERROR | ST_ON_ALLOC_UNPAIR_DEALLOCATE | \ + ST_ON_ALLOC_UNPAIR_IGNORE) +#define ST_TYPE_TRANSFORM_DEFAULT \ + (ST_DEFAULT_MAP_GUARD_PTRS_TO_STR_END | ST_REPORT_PRECISION_LOSS | \ + ST_REPORT_SIGN_CHANGE | ST_REPORT_SMALLER_ARRAYS | ST_REPORT_LARGER_ARRAYS) + +#define ST_POLICIES_DEFAULT_TRANSFER_ALL \ + (ST_DEFAULT_ALLOC_CASCADE_XFER | ST_DEFAULT_SKIP_STACK | \ + ST_DEFAULT_SKIP_LIB_STATE | ST_REPORT_NONXFERRED_ALLOCS | \ + ST_REPORT_NONXFERRED_UNPAIRED_ALLOCS | ST_MAP_STRINGS_DEFAULT | \ + ST_ON_ALLOC_UNPAIR_DEFAULT | ST_TYPE_TRANSFORM_DEFAULT) +#define ST_POLICIES_DEFAULT_TRANSFER_NONE \ + (ST_DEFAULT_TRANSFER_NONE | ST_DEFAULT_SKIP_STACK | \ + ST_DEFAULT_SKIP_LIB_STATE | ST_REPORT_NONXFERRED_ALLOCS | \ + ST_REPORT_NONXFERRED_UNPAIRED_ALLOCS | ST_MAP_STRINGS_DEFAULT | \ + ST_ON_ALLOC_UNPAIR_DEFAULT | ST_TYPE_TRANSFORM_DEFAULT) +#define ST_POLICIES_DEFAULT_TRANSFER_ASR \ + (ST_POLICIES_DEFAULT_TRANSFER_ALL | ST_REPORT_UNPAIRED_ALL) + +#define ST_POLICIES_DEFAULT ST_POLICIES_DEFAULT_TRANSFER_ALL + +/* Macros for predefined state transfer names. */ + +#define ADJUST_POINTER(local, remote, pointer) ( (local) + ((pointer) - (remote)) ) +#define ST_STR_BUFF_SIZE (MAGIC_MAX_NAME_LEN > MAGIC_MAX_TYPE_STR_LEN ? MAGIC_MAX_NAME_LEN : MAGIC_MAX_TYPE_STR_LEN) +#define USE_PRE_ALLOCATED_BUFFER(INFO) ((INFO)->init_buff_start) +#define EXEC_WITH_MAGIC_VARS(CMD, MAGIC_VARS) \ + do { \ + struct _magic_vars_t *__saved_vars = _magic_vars; \ + _magic_vars = (MAGIC_VARS); \ + CMD; \ + _magic_vars = __saved_vars; \ + } while(0); + +#define MAX_NUM_TYPENAMES 20 + +#define CHECK_SENTITY_PAIRS 1 +#define ST_DEBUG_LEVEL 1 +#define ST_DEBUG_DATA_TRANSFER 0 +#define CHECK_ASR 0 + +#define ST_ALLOW_RAW_UNPAIRED_TYPES 1 +#define ST_UNPAIRED_TYPES_RATIO_DEFAULT 0 +#define ST_UNPAIRED_STRUCT_TYPES_RATIO_DEFAULT 0 +#define FORCE_SOME_UNPAIRED_TYPES 1 +#define ST_TRANSFER_IDENTITY_FOR_NO_INNER_PTRS 1 + +#ifndef ST_ASSUME_RAW_COPY_BEFORE_TRANSFER +#define ST_ASSUME_RAW_COPY_BEFORE_TRANSFER 0 +#endif + +#if defined(__MINIX) +#define ST_IS_UNPAIRABLE_TYPE_OS(T) (sef_self_endpoint != VM_PROC_NR || strcmp((T)->name, "void")) +#else +#define ST_IS_UNPAIRABLE_TYPE_OS(T) 1 +#endif + +#if ST_ALLOW_RAW_UNPAIRED_TYPES +#define ST_IS_UNPAIRABLE_TYPE(T) (ST_IS_UNPAIRABLE_TYPE_OS(T) && (T)->type_id != MAGIC_TYPE_UNION) +#else +#define ST_IS_UNPAIRABLE_TYPE(T) \ + (ST_IS_UNPAIRABLE_TYPE_OS(T) \ + && !MAGIC_TYPE_IS_RAW_ARRAY(T) \ + && !((T)->type_id == MAGIC_TYPE_ARRAY && !strcmp((T)->contained_types[0]->type_str, "i8")) \ + && !(T)->ext) +#endif + +#define ST_IS_UNPAIRABLE_STRUCT_TYPE(T) \ + ((T)->type_id == MAGIC_TYPE_STRUCT) + +#define ST_FLAGS_PRINT(E) printf(", sf_flags(NDndsc)=%d%d%d%d%d%d", \ + MAGIC_STATE_EXTF_FLAG(E,ST_NEEDS_TRANSFER), MAGIC_STATE_EXTF_FLAG(E,ST_TRANSFER_DONE), \ + MAGIC_STATE_EXTF_FLAG(E,ST_ON_PTRXFER_SET_NULL), MAGIC_STATE_EXTF_FLAG(E,ST_ON_PTRXFER_SET_DEFAULT), \ + MAGIC_STATE_EXTF_FLAG(E,ST_ON_PTRXFER_SKIP), MAGIC_STATE_EXTF_FLAG(E,ST_ON_PTRXFER_CASCADE)); + +#define ST_SENTRY_PRINT(E,T) do { MAGIC_SENTRY_PRINT(E, T); ST_FLAGS_PRINT(E); if (MAGIC_SENTRY_IS_STRING(E)) printf(", string=\"%s\"", (ST_SENTRY_IS_CACHED(E) ? st_lookup_str_local_data(E) : (char*)(E)->address)); } while(0) +#define ST_DSENTRY_PRINT(E,T) do { MAGIC_DSENTRY_PRINT(E, T); ST_FLAGS_PRINT(&E->sentry); } while(0) +#define ST_FUNCTION_PRINT(E,T) do { MAGIC_FUNCTION_PRINT(E, T); ST_FLAGS_PRINT(E); } while(0) + +#define ST_CHECK_INIT() assert(st_init_done && "st_init() should be called first!") + +#define ST_SENTRY_IS_CACHED(E) (MAGIC_SENTRY_ID(E) >= 1 && MAGIC_SENTRY_ID(E) <= st_cached_magic_vars.sentries_num && st_cached_magic_vars.sentries[MAGIC_SENTRY_ID(E)-1].address == (E)->address) +#define ST_GET_CACHED_COUNTERPART(CE,T,CT,LE) do { \ + int i = (CE)->id - 1; \ + assert(i >= 0 && i < st_counterparts.T##_size); \ + LE = st_counterparts.CT[i].counterpart; \ + } while(0) +#define ST_SET_CACHED_COUNTERPART(CE,T,CT,LE) do { \ + int i = (CE)->id - 1; \ + assert(i >= 0 && i < st_counterparts.T##_size); \ + st_counterparts.CT[i].counterpart = LE; \ + } while(0) +#define ST_HAS_CACHED_COUNTERPART(CE,CT) (st_counterparts.CT[(CE)->id - 1].counterpart != NULL) + +#define ST_TYPE_IS_STATIC_CACHED_COUNTERPART(CE,LE) (((CE) >= &st_cached_magic_vars.types[0] && (CE) < &st_cached_magic_vars.types[st_cached_magic_vars.types_num]) && st_counterparts.types[(CE)->id - 1].counterpart == (LE)) +#define ST_TYPE_IS_DYNAMIC_CACHED_COUNTERPART(CE,LE) (MAGIC_TYPE_FLAG(CE,MAGIC_TYPE_DYNAMIC) && (CE)->type_id == MAGIC_TYPE_ARRAY && (LE)->type_id == MAGIC_TYPE_ARRAY && (CE)->num_child_types == (LE)->num_child_types && ST_TYPE_IS_STATIC_CACHED_COUNTERPART((CE)->contained_types[0], (LE)->contained_types[0])) +#define ST_TYPE_IS_CACHED_COUNTERPART(CE,LE) (ST_TYPE_IS_STATIC_CACHED_COUNTERPART(CE,LE) || ST_TYPE_IS_DYNAMIC_CACHED_COUNTERPART(CE,LE)) +#define ST_PTR_TYPE_IS_STATIC_CACHED_COUNTERPART(CE,LE) (((CE) >= &st_cached_magic_vars.types[0] && (CE) < &st_cached_magic_vars.types[st_cached_magic_vars.types_num]) && st_counterparts.ptr_types[(CE)->id - 1].counterpart == (LE)) +#define ST_PTR_TYPE_IS_DYNAMIC_CACHED_COUNTERPART(CE,LE) (MAGIC_TYPE_FLAG(CE,MAGIC_TYPE_DYNAMIC) && (CE)->type_id == MAGIC_TYPE_ARRAY && (LE)->type_id == MAGIC_TYPE_ARRAY && (CE)->num_child_types == (LE)->num_child_types && ST_PTR_TYPE_IS_STATIC_CACHED_COUNTERPART((CE)->contained_types[0], (LE)->contained_types[0])) +#define ST_PTR_TYPE_IS_CACHED_COUNTERPART(CE,LE) (ST_PTR_TYPE_IS_STATIC_CACHED_COUNTERPART(CE,LE) || ST_PTR_TYPE_IS_DYNAMIC_CACHED_COUNTERPART(CE,LE)) + + +/* Buffer allocation */ +PUBLIC void *st_cb_pages_allocate(st_init_info_t *info, uint32_t *phys, int num_pages); +PUBLIC void st_cb_pages_free(st_init_info_t *info, st_alloc_pages *current_page); +PUBLIC void *st_buff_allocate(st_init_info_t *info, size_t size); +PUBLIC void st_buff_cleanup(st_init_info_t *info); + +#endif /* ST_STATE_TRANSFER_H */ diff --git a/minix/llvm/include/st/typedefs.h b/minix/llvm/include/st/typedefs.h new file mode 100644 index 000000000..739be1f81 --- /dev/null +++ b/minix/llvm/include/st/typedefs.h @@ -0,0 +1,54 @@ +#ifndef ST_TYPEDEFS_H +#define ST_TYPEDEFS_H + +#include + +/* Typedefs for predefined state transfer names. */ +#define ST_DECLARE_STD_PTR_TYPEDEFS(PREFIX) \ + typedef void* PREFIX ## void_ptr_t; \ + typedef char* PREFIX ## char_ptr_t; \ + typedef short* PREFIX ## short_ptr_t; \ + typedef int* PREFIX ## int_ptr_t; \ + typedef long* PREFIX ## long_ptr_t; \ + typedef unsigned char* PREFIX ## uchar_ptr_t; \ + typedef unsigned short* PREFIX ## ushort_ptr_t; \ + typedef unsigned int* PREFIX ## uint_ptr_t; \ + typedef unsigned long* PREFIX ## ulong_ptr_t; \ + typedef float* PREFIX ## float_ptr_t; \ + typedef double* PREFIX ## double_ptr_t; \ + typedef uint8_t* PREFIX ## u8_ptr_t; \ + typedef uint16_t* PREFIX ## u16_ptr_t; \ + typedef uint32_t* PREFIX ## u32_ptr_t; \ + typedef uint64_t* PREFIX ## u64_ptr_t; \ + typedef int8_t* PREFIX ## i8_ptr_t; \ + typedef int16_t* PREFIX ## i16_ptr_t; \ + typedef int32_t* PREFIX ## i32_ptr_t + +#define ST_DECLARE_STD_PTRINT_TYPEDEFS(PREFIX) \ + typedef uint32_t PREFIX ## u32_t; \ + typedef int PREFIX ## int_t; \ + typedef long PREFIX ## long_t; \ + typedef unsigned int PREFIX ## uint_t; \ + typedef unsigned long PREFIX ## ulong_t + +#define ST_TYPENAME_NO_TRANSFER_NAMES "noxfer_*", "pthread_mutex_t", "siginfo_t", "epoll_data_t", "YYSTYPE" + ST_DECLARE_STD_PTR_TYPEDEFS(noxfer_); +#define ST_TYPENAME_IDENTITY_TRANSFER_NAMES "ixfer_*" + ST_DECLARE_STD_PTR_TYPEDEFS(ixfer_); +#define ST_TYPENAME_CIDENTITY_TRANSFER_NAMES "cixfer_*" + ST_DECLARE_STD_PTR_TYPEDEFS(cixfer_); +#define ST_TYPENAME_PTR_TRANSFER_NAMES "pxfer_*" + ST_DECLARE_STD_PTRINT_TYPEDEFS(pxfer_); +#define ST_TYPENAME_STRUCT_TRANSFER_NAMES "sxfer_*" +#ifdef __MINIX +#define ST_SENTRYNAME_NO_TRANSFER_NAMES "noxfer_*", "sef_*", "st_*", "_brksize", "etext" +#else +#define ST_SENTRYNAME_NO_TRANSFER_NAMES "noxfer_*", "st_*", "_brksize", "etext", "allocatedDescs*", "ep.*" /* nginx specific */ +#define ST_DSENTRYLIB_NO_TRANSFER_NAMES "*/libst.so", "*/libcommon.so", "*/libtaskctl.so" +#endif +#define ST_SENTRYNAME_IDENTITY_TRANSFER_NAMES "ixfer_*" +#define ST_SENTRYNAME_CIDENTITY_TRANSFER_NAMES "cixfer_*" +#define ST_SENTRYNAME_PTR_TRANSFER_NAMES "pxfer_*" + + +#endif /* ST_TYPEDEFS_H */ diff --git a/minix/llvm/static/Makefile.settings b/minix/llvm/static/Makefile.settings new file mode 100644 index 000000000..56b705745 --- /dev/null +++ b/minix/llvm/static/Makefile.settings @@ -0,0 +1,80 @@ +# THIS FILE IS AN EDITED VERSION OF A FILE GENERATED BY LLVM-APPS +# XXX EDIT AT LEAST THIS PART +_MINIX_ARCH=i386 +_MINIX_ROOT=/home/myname/path/to/minix +_MINIX_TOOLS_DIR=/home/myname/path/to/obj.i386/tooldir.Linux-myversion + +########################################################### +# llvm-apps settings for Minix binary instrumentation +########################################################### +_MINIX_LLVM_DIR=$(_MINIX_ROOT)/minix/llvm +_MINIX_OBJ_DIR=$(_MINIX_ROOT)/../obj.$(_MINIX_ARCH) +_MINIX_OBJ_LLVM_DIR=$(_MINIX_ROOT)/../obj_llvm.$(_MINIX_ARCH) +_MINIX_SYSROOT=$(_MINIX_OBJ_DIR)/destdir.$(_MINIX_ARCH) + +########################################################### +# Main configuration (override in common.overrides.*inc to match your settings) +########################################################### +HAVE_LLVM=1 +LLVMBASEDIR=$(_MINIX_LLVM_DIR) +LLVMPREFIX=$(_MINIX_OBJ_LLVM_DIR)/Release+Asserts +LLVM_TWOSTEP_LINKING_WITH_GOLD=0 +LLVM_TWOSTEP_LINKING_WITH_GOLD_USES_LLC=0 +LLVM_OUTPUT_TRG_DIR= +LLVM_CAP_ALL=CAP_AUDIT_CONTROL,CAP_AUDIT_WRITE,CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_DAC_READ_SEARCH,CAP_FOWNER,CAP_FSETID,CAP_IPC_LOCK,CAP_IPC_OWNER,CAP_KILL,CAP_LEASE,CAP_LINUX_IMMUTABLE,CAP_MAC_ADMIN,CAP_MAC_OVERRIDE,CAP_MKNOD,CAP_NET_ADMIN,CAP_NET_BIND_SERVICE,CAP_NET_BROADCAST,CAP_NET_RAW,CAP_SETGID,CAP_SETFCAP,CAP_SETPCAP,CAP_SETUID,CAP_SYS_ADMIN,CAP_SYS_BOOT,CAP_SYS_CHROOT,CAP_SYS_MODULE,CAP_SYS_NICE,CAP_SYS_PACCT,CAP_SYS_PTRACE,CAP_SYS_RAWIO,CAP_SYS_RESOURCE,CAP_SYS_TIME,CAP_SYS_TTY_CONFIG,CAP_SYSLOG,CAP_SYS_MODULE +########################################################### + +########################################################### +# Common variables +########################################################### +ABS_ROOT=$(LLVMBASEDIR) + +PERF_PATH=/usr/bin/perf +LLVMDIR=$(ABS_ROOT) +LLVMINC=$(LLVMDIR)/include +LLVMLIB=$(LLVMDIR)/lib +INSTALL_DIR=$(ABS_ROOT)/bin + +LLVMSECTIONIFY_SO=$(INSTALL_DIR)/sectionify.so +LLVMAOPIFY_SO=$(INSTALL_DIR)/aopify.so +LLVMMAGIC_ST_IN_LIBST=0 + +CC=clang +CXX=clang++ +CFLAGS=-fasynchronous-unwind-tables -g -I$(LLVMINC) +########################################################### + +########################################################### +# LLVM gold plugin support (see README.llvm for details) +# +# Note: LLVMGOLD_PREFIX below should point to a valid LLVM 2.9 (+LLVMGOLD_CC=llvm-gcc) [or LLVM >= 3.0 (+LLVMGOLD_CC=clang)] installation with gold plugin support (binutils >=2.22) +########################################################### +LLVMGOLD_HAS_LTO_DISABLE_OPT=1 +LLVMGOLD_PREFIX=$(LLVMPREFIX) +LLVMGOLD_PLUGIN=$(_MINIX_LLVM_DIR)/bin/LLVMgold.so + +LLVMGOLD_CC=$(_MINIX_TOOLS_DIR)/bin/i586-elf32-minix-clang -flto +LLVMGOLD_CXX=$(_MINIX_TOOLS_DIR)/bin/i586-elf32-minix-clang++ -flto +LLVMGOLD_AR=ar --plugin $(LLVMGOLD_PLUGIN) +LLVMGOLD_RANLIB=$(LLVMGOLD_AR) -s + +LLVMGOLD_AR_FLAGS=--plugin $(LLVMGOLD_PLUGIN) -cru +LLVMGOLD_CFLAGS=-fasynchronous-unwind-tables -g -D_MINIX -D_POSIX_SOURCE -D_SYSTEM -Wno-long-long --sysroot=$(_MINIX_SYSROOT) -I$(LLVMINC) -I$(_MINIX_OBJ_LLVM_DIR)/include/llvm -I$(_MINIX_ROOT)/external/bsd/llvm/dist/llvm/include -I$(_MINIX_OBJ_LLVM_DIR)/include -I$(_MINIX_SYSROOT)/usr/include +LLVMGOLD_LINK=-Wl,--plugin -Wl,$(LLVMGOLD_PLUGIN) +LLVMGOLD_LINKFLAGS=-Wl,-plugin-opt=-disable-fp-elim -Wl,-plugin-opt=-disable-inlining -Wl,-plugin-opt=also-emit-llvm +LLVMGOLD_LINKCOMMONFLAGS=-L$(_MINIX_OBJ_DIR)/destdir.$(_MINIX_ARCH)/usr/lib -rdynamic +LLVMGOLD_LIBS= +LLVMGOLD_LDFLAGS=$(LLVMGOLD_LINK) $(LLVMGOLD_LINKFLAGS) $(LLVMGOLD_LINKCOMMONFLAGS) $(LLVMGOLD_LIBS) +LLVMGOLD_OPTFLAGS=-disable-internalize -mem2reg -std-compile-opts +LLVMGOLD_LLCFLAGS=--disable-fp-elim +LLVMGOLD_TSLINK_PARTIALFLAGS=-Wl,-r -nostdlib +LLVMGOLD_TSLINK_FINALFLAGS=-B$(LLVMGOLD_PREFIX)/bfd_bin +LLVMGOLD_OPTIMIZED=1 + +########################################################### + +BUILD_LLVMAPPS_FOR_MINIX=yes +GEN_GOLD_PLUGIN=yes +REBUILD_MINIX=yes +ARCH_NAME=x86 +ARCH_BITS=32 diff --git a/minix/llvm/static/magic/Makefile b/minix/llvm/static/magic/Makefile new file mode 100644 index 000000000..8fac9ee9c --- /dev/null +++ b/minix/llvm/static/magic/Makefile @@ -0,0 +1,29 @@ +#Makefile for creating the magic static library + +MODULE = magic +OBJS = magic.o magic_analysis.o magic_asr.o magic_eval_lib.o magic_eval.o magic_mem.o magic_range.o magic_splay_tree.o magic_sentry.o magic_selement.o +HEADERS = $(wildcard $(LLVMINC)/*.h) $(wildcard $(LLVMINC)/st/*.h) + +USE_SECTIONIFY=YES +SECTIONIFY_NO_OVERRIDE=yes +SECTIONIFY_DATA_SECTION_MAP=^_____magic_instr_.*/magic_instr_data,.*/magic_data +SECTIONIFY_FUNCTION_SECTION_MAP=.*/magic_functions + +OBJS += minix/magic_util.o minix/magic_ds.o +HEADERS += $(wildcard minix/*.h) + +OBJS+=magic_st.bcc + +include Makefile.inc + +CFLAGS += -I$(_MINIX_ROOT)/minix/servers + +# XXX: there is essential code in assert() statements, so force asserts on.. +CFLAGS += -UNDEBUG + +magic_st.bcc: + make -f Makefile.magic_st $@ + +magic_st.o: + make -f Makefile.magic_st $@ + diff --git a/minix/llvm/static/magic/Makefile.inc b/minix/llvm/static/magic/Makefile.inc new file mode 100644 index 000000000..91b99e08f --- /dev/null +++ b/minix/llvm/static/magic/Makefile.inc @@ -0,0 +1,57 @@ + +include ../Makefile.settings + +MODULE_NAME=$(MODULE).bcc + +CFLAGS += $(CXXFLAGS) -Wall -g -Wno-long-long +CFLAGS += -D__MINIX -D_MINIX_SYSTEM + +LLVM_VERSION=$(shell $(LLVMPREFIX)/bin/llvm-config --version | cut -d"." -f1,2 | sed "s/[^0-9]//g") + +HAVE_NOCONSTRUCTOR_PRIORITY = $(shell expr $(LLVM_VERSION) \>= 30) +ifeq ($(HAVE_NOCONSTRUCTOR_PRIORITY),0) +CFLAGS += -DHAVE_NOCONSTRUCTOR_PRIORITY=1 +endif + +ifeq ($(USE_SECTIONIFY),YES) +LOPT_FLAGS+=-load=$(LLVMSECTIONIFY_SO) -sectionify -sectionify-no-override -sectionify-data-section-map=$(SECTIONIFY_DATA_SECTION_MAP) -sectionify-function-section-map=$(SECTIONIFY_FUNCTION_SECTION_MAP) +ifeq (SECTIONIFY_NO_OVERRIDE,YES) +LOPT_FLAGS+=-sectionify-no-override +endif +endif + +V?=0 +ifneq ($V,0) +QUIET= +ECHO:=@\# +QMAKE=VERBOSE=1 make +else +QUIET= @ +ECHO= echo +QMAKE=make -s +endif + +$(MODULE_NAME): $(OBJS) $(HEADERS) $(COMMON_BCCS) + $(QUIET) $(ECHO) " [GOLD_LINK] $@.o" + $(QUIET) $(LLVMGOLD_CC) $(CFLAGS) $(LLVMGOLD_CFLAGS) $(LLVMGOLD_LDFLAGS) -shared -o $@.o $(OBJS) $(COMMON_BCCS) + $(QUIET) $(ECHO) " [OPT] $@" + $(QUIET) $(LLVMPREFIX)/bin/opt $(LOPT_FLAGS) -o $@ $@.o.bc + +all: $(MODULE_NAME) + +%.o: %.c $(HEADERS) + $(QUIET) $(ECHO) " [GOLD_CC] $<" + $(QUIET) $(LLVMGOLD_CC) $(CFLAGS) $(LLVMGOLD_CFLAGS) $(INCLUDES) $(INCLUDES_$<) -c -o $@ $< + +install: $(INSTALL_DIR)/$(MODULE_NAME) + +$(INSTALL_DIR)/$(MODULE_NAME): $(MODULE_NAME) + install -c -D -m 744 $? $@ + +clean: $(EXTRA_CLEAN) + $(QUIET) $(ECHO) " [RM] *.BCC *.bcc *.bc *.BCL *.BCL.sh *.bcl $(OBJS) *.s $(COMMON_BCCS)" + $(QUIET) rm -f *.BCC *.bcc *.bc *.BCL *.BCL.sh *.bcl *.o $(OBJS) *.s $(COMMON_BCCS) + +distclean: clean + $(QUIET) $(ECHO) " [RM] $(INSTALL_DIR)/$(MODULE_NAME)" + $(QUIET) rm -f $(INSTALL_DIR)/$(MODULE_NAME) diff --git a/minix/llvm/static/magic/Makefile.magic_st b/minix/llvm/static/magic/Makefile.magic_st new file mode 100644 index 000000000..9ec7c54cd --- /dev/null +++ b/minix/llvm/static/magic/Makefile.magic_st @@ -0,0 +1,11 @@ + +MODULE = magic_st + +OBJS = magic_st.o + +USE_SECTIONIFY=YES +SECTIONIFY_DATA_SECTION_MAP=.*/magic_data_st +SECTIONIFY_FUNCTION_SECTION_MAP=.*/magic_functions_st + +include Makefile.inc + diff --git a/minix/llvm/static/magic/magic.c b/minix/llvm/static/magic/magic.c new file mode 100644 index 000000000..661ff334f --- /dev/null +++ b/minix/llvm/static/magic/magic.c @@ -0,0 +1,2585 @@ +#include +#include +#include +#include +#include +#include +#include +#if MAGIC_MEM_USAGE_OUTPUT_CTL +#include +#endif + +/* Workaround for extern-only structs. */ +#ifndef __MINIX +#include +EXTERN FILE *stdout; +PUBLIC FILE **UNUSED(_____magic_instr_FILE_unused) = &stdout; + +#include +PUBLIC WINDOW *UNUSED(_____magic_instr_WINDOW_unused); +#endif + +#include +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;itype_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 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 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;inum_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;icontained_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; inum_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; inum_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; inum_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;icontained_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;itype, (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;imember_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;inum_names;i++) { + size += strlen(type->names[i])+1; + } + } + if(flags & MAGIC_SIZE_COMP_TYPES) { + if(MAGIC_TYPE_HAS_COMP_TYPES(type)) { + int num; + MAGIC_TYPE_NUM_COMP_TYPES(type, &num); + size += sizeof(*(type->compatible_types))*num; + } + } + + return size; +} + +/*===========================================================================* + * magic_types_get_size * + *===========================================================================*/ +PUBLIC size_t magic_types_get_size(int flags) +{ + size_t size; + int i; + + size = 0; + for(i=0;i<_magic_types_num;i++) { + size += magic_type_get_size(&_magic_types[i], flags); + } + + return size; +} + +/*===========================================================================* + * magic_function_get_size * + *===========================================================================*/ +PUBLIC size_t magic_function_get_size(struct _magic_function *function, int flags) +{ + size_t size; + + size = sizeof(function->type) + sizeof(function->flags) + sizeof(function->address); + + if(flags & MAGIC_SIZE_NAMES) { + size += sizeof(function->name) + strlen(function->name)+1; + } + + return size; +} + +/*===========================================================================* + * magic_functions_get_size * + *===========================================================================*/ +PUBLIC size_t magic_functions_get_size(int flags) +{ + size_t size; + int i; + + size = 0; + for(i=0;i<_magic_functions_num;i++) { + size += magic_function_get_size(&_magic_functions[i], flags); + } + + return size; +} + +/*===========================================================================* + * magic_dfunctions_get_size * + *===========================================================================*/ +PUBLIC size_t magic_dfunctions_get_size(int flags) +{ + size_t size; + struct _magic_dfunction* dfunction; + struct _magic_function* function; + + size = 0; + MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function, + size += magic_function_get_size(function, flags); + ); + + return size; +} + +/*===========================================================================* + * magic_sentry_get_size * + *===========================================================================*/ +PUBLIC size_t magic_sentry_get_size(struct _magic_sentry *sentry, int flags) +{ + size_t size; + + size = sizeof(sentry->type) + sizeof(sentry->flags); + + if(MAGIC_SENTRY_IS_DSENTRY(sentry)) { + struct _magic_dsentry *dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry); + if(flags & MAGIC_SIZE_DSENTRY_NAMES) { + size += sizeof(sentry->name) + strlen(sentry->name)+1; + if(dsentry->parent_name) { + size += sizeof(dsentry->parent_name) + strlen(dsentry->parent_name)+1; + } + } + if(sentry->type == &dsentry->type) { + size += sizeof(dsentry->type.num_child_types); + } + size += sizeof(dsentry->next); + } + else { + size += sizeof(sentry->address); + if(flags & MAGIC_SIZE_NAMES) { + size += sizeof(sentry->name) + strlen(sentry->name)+1; + } + } + + return size; +} + +/*===========================================================================* + * magic_sentries_get_size * + *===========================================================================*/ +PUBLIC size_t magic_sentries_get_size(int flags) +{ + size_t size; + int i; + + size = 0; + for(i=0;i<_magic_sentries_num;i++) { + size += magic_sentry_get_size(&_magic_sentries[i], flags); + } + + return size; +} + +/*===========================================================================* + * magic_dsentries_get_size * + *===========================================================================*/ +PUBLIC size_t magic_dsentries_get_size(int flags) +{ + size_t size; + struct _magic_dsentry *prev_dsentry, *dsentry; + struct _magic_sentry* sentry; + + size = 0; + MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry, + if(!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) { + size += magic_sentry_get_size(sentry, flags); + } + ); + + return size; +} + +/*===========================================================================* + * magic_dsindex_get_size * + *===========================================================================*/ +PUBLIC size_t magic_dsindex_get_size(struct _magic_dsindex *dsindex, int flags) +{ + size_t size; + + size = sizeof(dsindex->type) + sizeof(dsindex->flags); + + if(flags & MAGIC_SIZE_DSINDEX_NAMES) { + size += sizeof(dsindex->parent_name) + strlen(dsindex->parent_name)+1; + size += sizeof(dsindex->name) + strlen(dsindex->name)+1; + } + + return size; +} + +/*===========================================================================* + * magic_dsindexes_get_size * + *===========================================================================*/ +PUBLIC size_t magic_dsindexes_get_size(int flags) +{ + size_t size; + int i; + + size = 0; + for(i=0;i<_magic_dsindexes_num;i++) { + size += magic_dsindex_get_size(&_magic_dsindexes[i], flags); + } + + return size; +} + +/*===========================================================================* + * magic_sodesc_get_size * + *===========================================================================*/ +PUBLIC size_t magic_sodesc_get_size(struct _magic_sodesc *sodesc, int flags) +{ + return sizeof(struct _magic_sodesc); +} + +/*===========================================================================* + * magic_sodescs_get_size * + *===========================================================================*/ +PUBLIC size_t magic_sodescs_get_size(int flags) +{ + size_t size; + struct _magic_sodesc* sodesc; + + size = 0; + MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc, + size += magic_sodesc_get_size(sodesc, flags); + ); + + return size; +} + +/*===========================================================================* + * magic_dsodesc_get_size * + *===========================================================================*/ +PUBLIC size_t magic_dsodesc_get_size(struct _magic_dsodesc *dsodesc, int flags) +{ + return sizeof(struct _magic_dsodesc); +} + +/*===========================================================================* + * magic_dsodescs_get_size * + *===========================================================================*/ +PUBLIC size_t magic_dsodescs_get_size(int flags) +{ + size_t size; + struct _magic_dsodesc* dsodesc; + + size = 0; + MAGIC_DSODESC_ITER(_magic_first_dsodesc, dsodesc, + size += magic_dsodesc_get_size(dsodesc, flags); + ); + + return size; +} + +/*===========================================================================* + * magic_metadata_get_size * + *===========================================================================*/ +PUBLIC size_t magic_metadata_get_size(int flags) +{ + size_t size = 0; + + size += magic_types_get_size(flags); + size += magic_functions_get_size(flags); + size += magic_dfunctions_get_size(flags); + size += magic_sentries_get_size(flags); + size += magic_dsentries_get_size(flags); + size += magic_dsindexes_get_size(flags); + size += magic_dsodescs_get_size(flags); + + return size; +} + +/*===========================================================================* + * magic_sentries_data_get_size * + *===========================================================================*/ +PUBLIC size_t magic_sentries_data_get_size(int flags) +{ + size_t size; + int i; + + size = 0; + for(i=0;i<_magic_sentries_num;i++) { + size += _magic_sentries[i].type->size; + } + + return size; +} + +/*===========================================================================* + * magic_dsentries_data_get_size * + *===========================================================================*/ +PUBLIC size_t magic_dsentries_data_get_size(int flags) +{ + size_t size; + struct _magic_dsentry *prev_dsentry, *dsentry; + struct _magic_sentry* sentry; + + size = 0; + MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry, + if(!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) { + size += sentry->type->size; + if(MAGIC_STATE_FLAG(sentry, MAGIC_STATE_HEAP)) { + /* Assume a couple of words for malloc header. */ + size += 2*sizeof(void*); + } + } + ); + + return size; +} + +/*===========================================================================* + * magic_other_data_get_size * + *===========================================================================*/ +PUBLIC size_t magic_other_data_get_size(int flags) +{ + size_t size = 0; + + MAGIC_DSENTRY_LOCK(); + magic_range_is_stack(NULL); + MAGIC_DSENTRY_UNLOCK(); + size += MAGIC_RANGE_SIZE(magic_stack_range); + size += MAGIC_RANGE_SIZE(magic_text_range); + + return size; +} + +/*===========================================================================* + * magic_data_get_size * + *===========================================================================*/ +PUBLIC size_t magic_data_get_size(int flags) +{ + size_t size = 0; + + size += magic_sentries_data_get_size(flags); + size += magic_dsentries_data_get_size(flags); + size += magic_other_data_get_size(flags); + + return size; +} + +/*===========================================================================* + * magic_print_size_stats * + *===========================================================================*/ +PUBLIC void magic_print_size_stats(int flags) +{ + size_t sentries_data_size, sentries_metadata_size; + size_t dsentries_data_size, dsentries_metadata_size; + size_t data_size, metadata_size; + int dsentries_num; + sentries_data_size = magic_sentries_data_get_size(flags); + sentries_metadata_size = magic_sentries_get_size(flags); + dsentries_data_size = magic_dsentries_data_get_size(flags); + dsentries_metadata_size = magic_dsentries_get_size(flags); + data_size = magic_data_get_size(flags); + metadata_size = magic_metadata_get_size(flags); + MAGIC_DSENTRY_NUM(_magic_first_dsentry, &dsentries_num); + _magic_printf("--------------------------------------------------------\n"); + _magic_printf("magic_print_size_stats: Printing size stats:\n"); + _magic_printf(" - sentries: # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", _magic_sentries_num, sentries_data_size, sentries_metadata_size, sentries_data_size+sentries_metadata_size, ((double)sentries_metadata_size)/sentries_data_size); + _magic_printf(" - dsentries: # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", dsentries_num, dsentries_data_size, dsentries_metadata_size, dsentries_data_size+dsentries_metadata_size, ((double)dsentries_metadata_size)/dsentries_data_size); + _magic_printf(" - other: # %6d, data %8d\n", 2, magic_other_data_get_size(flags)); + _magic_printf(" - state all: # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", _magic_sentries_num+dsentries_num, sentries_data_size+dsentries_data_size, metadata_size, sentries_data_size+dsentries_data_size+metadata_size, ((double)metadata_size)/(sentries_data_size+dsentries_data_size)); + _magic_printf(" - all: # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", _magic_sentries_num+dsentries_num+2, data_size, metadata_size, data_size+metadata_size, ((double)metadata_size)/data_size); + _magic_printf("--------------------------------------------------------\n"); + _magic_printf("magic_print_size_stats: Printing metadata size breakdown:\n"); + _magic_printf(" - types: # %6d, metadata %8d\n", _magic_types_num, magic_types_get_size(flags)); + _magic_printf(" - functions: # %6d, metadata %8d\n", _magic_functions_num, magic_functions_get_size(flags)); + _magic_printf(" - dfunctions # %6d, metadata %8d\n", 0, magic_dfunctions_get_size(flags)); + _magic_printf(" - sentries: # %6d, metadata %8d\n", _magic_sentries_num, sentries_metadata_size); + _magic_printf(" - dsentries: # %6d, metadata %8d\n", dsentries_num, dsentries_metadata_size); + _magic_printf(" - dsindexes: # %6d, metadata %8d\n", _magic_dsindexes_num, magic_dsindexes_get_size(flags)); + _magic_printf(" - dsodescs: # %6d, metadata %8d\n", 0, magic_dsodescs_get_size(flags)); + _magic_printf("--------------------------------------------------------\n"); +} + diff --git a/minix/llvm/static/magic/magic_analysis.c b/minix/llvm/static/magic/magic_analysis.c new file mode 100644 index 000000000..bfb9e440e --- /dev/null +++ b/minix/llvm/static/magic/magic_analysis.c @@ -0,0 +1,1065 @@ + +#include + +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;iu.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;iu.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;iu.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;iu.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(;iu.ptr.trg_selements[i]; + trg_stats = sel_analyzed->u.ptr.trg_stats[i]; + _magic_printf("%s%d|%c=", (i==0 ? ": " : ", "), i+1, MAGIC_SEL_ANALYZED_TRG_STATS_C(trg_stats)); + MAGIC_SELEMENT_PRINT(trg_selement, flags|MAGIC_SKIP_COMP_TYPES); + } +} + +/*===========================================================================* + * magic_selement_type_cast * + *===========================================================================*/ +PUBLIC _magic_selement_t* magic_selement_type_cast( + _magic_selement_t *selement, int flags, const struct _magic_type* type, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats) +{ + _magic_sel_stats_t my_sel_stats; + + selement->type = type; + if(sel_analyzed) { + magic_selement_analyze(selement, flags, + sel_analyzed, sel_stats ? sel_stats : &my_sel_stats); + } + return selement; +} + diff --git a/minix/llvm/static/magic/magic_asr.c b/minix/llvm/static/magic/magic_asr.c new file mode 100644 index 000000000..5c576d286 --- /dev/null +++ b/minix/llvm/static/magic/magic_asr.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include + +#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;jnext; + } + + if(pos == 0){ + first_dsentry = first_dsentry->next; + }else{ + prev_dsentry->next = dsentry->next; + } + + dsentry->next = NULL; + last_dsentry->next = dsentry; + last_dsentry = dsentry; + } + *first_dsentry_ptr = first_dsentry; +} + +PUBLIC void magic_asr_init(){ + int seed, heap_offset; + if(_magic_asr_seed){ + seed = _magic_asr_seed; + }else{ + seed = magic_rand_seed(); + } + magic_srand(seed); + + heap_offset = magic_asr_get_padding_size(MAGIC_STATE_HEAP|MAGIC_ASR_FLAG_INIT); + if(heap_offset){ + sbrk(heap_offset); + } +} diff --git a/minix/llvm/static/magic/magic_eval.c b/minix/llvm/static/magic/magic_eval.c new file mode 100644 index 000000000..469e4c587 --- /dev/null +++ b/minix/llvm/static/magic/magic_eval.c @@ -0,0 +1,216 @@ +#include +#include +#include + +#define DEBUG MAGIC_DEBUG_SET(0) + +#if DEBUG +#define MAGIC_EVAL_PRINTF _magic_printf +#else +#define MAGIC_EVAL_PRINTF magic_null_printf +#endif + +PRIVATE int magic_eval_print_style = MAGIC_EVAL_PRINT_STYLE_DEFAULT; + +/*===========================================================================* + * magic_eval_get_var_cb * + *===========================================================================*/ +PRIVATE struct val* magic_eval_get_var_cb(char* name, struct val* val) +{ + _magic_selement_t selement; + int ret; + double dvalue; + void *pvalue; + unsigned long uvalue; + long ivalue; + char vvalue; + struct _magic_dsentry dsentry_buff; + MAGIC_EVAL_PRINTF("magic_eval_get_var_cb: %s requested\n", name); + ret = magic_selement_lookup_by_name(name, &selement, &dsentry_buff); + if(ret < 0) { + return NULL; + } + val->type = T_INT; + switch(selement.type->type_id) { + case MAGIC_TYPE_FLOAT: + dvalue = magic_selement_to_float(&selement); + val->type = T_REAL; + val->rval = dvalue; + break; + + case MAGIC_TYPE_POINTER: + pvalue = magic_selement_to_ptr(&selement); + val->ival = (long) pvalue; + break; + + case MAGIC_TYPE_INTEGER: + case MAGIC_TYPE_ENUM: + if(MAGIC_TYPE_FLAG(selement.type, MAGIC_TYPE_UNSIGNED)) { + uvalue = magic_selement_to_unsigned(&selement); + val->ival = (long) uvalue; + } + else { + ivalue = magic_selement_to_int(&selement); + val->ival = ivalue; + } + break; + + case MAGIC_TYPE_VOID: + vvalue = *((char*) selement.address); + val->ival = (long) vvalue; + break; + + default: + return NULL; + break; + } + + if(magic_eval_print_style & MAGIC_EVAL_PRINT_VAR_VALUES) { + if(val->type == T_INT) { + _magic_printf("VAR: %s = %ld\n", name, val->ival); + } + else { + _magic_printf("VAR: %s = %g\n", name, val->rval); + } + } + + return val; +} + +/*===========================================================================* + * magic_eval_get_func_result_cb * + *===========================================================================*/ +PRIVATE struct val* magic_eval_get_func_result_cb(char* name, struct val* arg, + struct val* ret) +{ + struct _magic_function *function; + magic_eval_func_t magic_eval_func; + long result, iarg; + MAGIC_EVAL_PRINTF("magic_eval_get_func_result_cb: %s requested\n", name); + if(strncmp(MAGIC_EVAL_FUNC_PREFIX, name, strlen(MAGIC_EVAL_FUNC_PREFIX))) { + return NULL; + } + + function = magic_function_lookup_by_name(NULL, name); + if(!function) { + return NULL; + } + magic_eval_func = (magic_eval_func_t) (long) function->address; + iarg = arg->type == T_INT ? arg->ival : (long) arg->rval; + result = magic_eval_func(iarg); + ret->type = T_INT; + ret->ival = result; + + if(magic_eval_print_style & MAGIC_EVAL_PRINT_FUNC_RESULTS) { + _magic_printf("FUNCTION: %s(%ld) = %ld\n", name, iarg, result); + } + + return ret; +} + +/*===========================================================================* + * magic_eval_init * + *===========================================================================*/ +PUBLIC void magic_eval_init() +{ + eval_set_cb_get_var(magic_eval_get_var_cb); + eval_set_cb_get_func_result(magic_eval_get_func_result_cb); +} + +/*===========================================================================* + * magic_eval * + *===========================================================================*/ +PRIVATE int magic_eval(char *expr, struct val* result) +{ + int ret; + MAGIC_EVAL_PRINTF("magic_eval: Evaluating expression %s\n", expr); + ret = evaluate(expr, result, NULL); + switch(ret) { + case ERROR_SYNTAX: + ret = MAGIC_EINVAL; + break; + case ERROR_FUNCNOTFOUND: + case ERROR_VARNOTFOUND: + ret = MAGIC_ENOENT; + break; + case ERROR_NOMEM: + ret = MAGIC_ENOMEM; + break; + case ERROR_DIV0: + ret = MAGIC_EBADMSTATE; + break; + case RESULT_OK: + ret = 0; + break; + default: + ret = MAGIC_EGENERIC; + break; + } + + return ret; +} + +/*===========================================================================* + * magic_eval_int * + *===========================================================================*/ +PUBLIC int magic_eval_int(char *expr, long *result) +{ + struct val val_res; + int ret; + ret = magic_eval(expr, &val_res); + if(ret < 0) { + return ret; + } + *result = val_res.type == T_INT ? val_res.ival : (long) val_res.rval; + return 0; +} + +/*===========================================================================* + * magic_eval_bool * + *===========================================================================*/ +PUBLIC int magic_eval_bool(char *expr, char *result) +{ + struct val val_res; + int ret; + ret = magic_eval(expr, &val_res); + if(ret < 0) { + return ret; + } + if(val_res.type != T_INT) { + return MAGIC_EINVAL; + } + *result = val_res.ival == 0 ? 0 : 1; + return 0; +} + +/*===========================================================================* + * magic_eval_float * + *===========================================================================*/ +PUBLIC int magic_eval_float(char *expr, double *result) +{ + struct val val_res; + int ret; + ret = magic_eval(expr, &val_res); + if(ret < 0) { + return ret; + } + *result = val_res.type == T_INT ? (double) val_res.ival : val_res.rval; + return 0; +} + +/*===========================================================================* + * magic_eval_get_print_style * + *===========================================================================*/ +PUBLIC int magic_eval_get_print_style() +{ + return magic_eval_print_style; +} + +/*===========================================================================* + * magic_eval_set_print_style * + *===========================================================================*/ +PUBLIC void magic_eval_set_print_style(int style) +{ + magic_eval_print_style = style; +} + diff --git a/minix/llvm/static/magic/magic_eval_lib.c b/minix/llvm/static/magic/magic_eval_lib.c new file mode 100644 index 000000000..9aa8d209c --- /dev/null +++ b/minix/llvm/static/magic/magic_eval_lib.c @@ -0,0 +1,1159 @@ +/* evaluate.c (C) 2000-2002 Kyzer/CSG. */ +/* Released under the terms of the GNU General Public Licence version 2. */ + +#include "magic_eval_lib.h" +#include +#include +#include +#include +#include + +#if USE_MATH_LIB +#include +#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 MEM_BUFFER_LEN) { +#if MEM_DEBUG + printf("mem_alloc: out of mem\n"); +#endif + return NULL; + } + mem = (struct memh *) &mem_buffer[n][mem_idx_n]; + mem_idx[n] += len; + mem->next = mh->next; + mh->next = mem; + return mem->ptr = (void *) &mem[1]; +} + +void free_mem(struct memh *mh) { + int n = MEM_HEADER_TO_N(mh); + mem_idx[n] = 0; +#if MEM_DEBUG + printf("free_mem: n is %d\n", n); +#endif +} + +#endif + +/* creates an empty variable table */ +struct vartable *create_vartable() { + struct memh *mh = create_mem(); + struct vartable *vt; + if(!mh) { + return NULL; + } + vt = (struct vartable *) mem_alloc(mh, sizeof(struct vartable)); + if (mh && vt) vt->mh = mh, vt->first = NULL; else free_mem(mh); + return vt; +} + +/* frees a variable table */ +void free_vartable(struct vartable *vt) { + free_mem(vt->mh); +} + +/* gets a variable out of a variable table */ +struct var *get_var(struct vartable *vt, char *name) { + struct var *v; + if (!vt || !name) return NULL; + for (v = vt->first; v; v = v->next) if (same_str(v->name, name)) return v; + return NULL; +} + +/* creates a new variable in a variable table */ +struct var *put_var(struct vartable *vt, char *name, struct val *value) { + struct var *v; + char *n; + + if (!vt || !name || !value) return NULL; + + if ((v = get_var(vt, name))) { + v->val = *value; + return v; + } + + v = (struct var *) mem_alloc(vt->mh, sizeof(struct var)); + n = (char *) mem_alloc(vt->mh, strlen(name)+1); + if (v && n) { + strcpy(n, name); + v->name = n; + v->val = *value; + v->next = vt->first; + vt->first = v; + return v; + } + return NULL; +} diff --git a/minix/llvm/static/magic/magic_mem.c b/minix/llvm/static/magic/magic_mem.c new file mode 100644 index 000000000..77b2eb203 --- /dev/null +++ b/minix/llvm/static/magic/magic_mem.c @@ -0,0 +1,2108 @@ + +#ifdef _FILE_OFFSET_BITS +#undef _FILE_OFFSET_BITS +#endif +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include + +#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 +#include +#include +#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 + +/* 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;iname, name); + strcpy(obdsentry->parent_name, parent_name); + flags |= MAGIC_STATE_OUT_OF_BAND; + ret = magic_create_dsentry(MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry), data_ptr, type, + size, flags, obdsentry->name, obdsentry->parent_name); + + MAGIC_MEM_WRAPPER_LEND(); + + if(ret < 0) { + return NULL; + } + assert(!MAGIC_OBDSENTRY_IS_FREE(obdsentry)); + + return obdsentry; +} + +/*===========================================================================* + * magic_update_dsentry_state * + *===========================================================================*/ +PUBLIC int magic_update_dsentry_state(struct _magic_dsentry *dsentry, + unsigned long state) +{ + int ret = 0; + unsigned long old_state; + unsigned long num_dead_dsentries; + unsigned long size, size_dead_dsentries; + size = MAGIC_DSENTRY_TO_SENTRY(dsentry)->type->size; + + switch(state) { + case MAGIC_DSENTRY_MSTATE_FREED: + old_state = MAGIC_CAS(&dsentry->magic_state, MAGIC_DSENTRY_MSTATE_DEAD, + MAGIC_DSENTRY_MSTATE_FREED); + if(old_state != MAGIC_DSENTRY_MSTATE_DEAD) { + ret = MAGIC_EBADMSTATE; + break; + } + if (!MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(dsentry), MAGIC_STATE_MEMBLOCK)) { + num_dead_dsentries = MAGIC_FAS(&magic_num_dead_dsentries, 1) - 1; + size_dead_dsentries = MAGIC_FAS(&magic_size_dead_dsentries, size) - size; + MAGIC_MEM_PRINTF("magic_update_dsentry_state: --magic_num_dead_dsentries (num=%d, size=%d)\n", num_dead_dsentries, size_dead_dsentries); + } + break; + case MAGIC_DSENTRY_MSTATE_DEAD: + old_state = MAGIC_CAS(&dsentry->magic_state, MAGIC_DSENTRY_MSTATE_ALIVE, + MAGIC_DSENTRY_MSTATE_DEAD); + if(old_state != MAGIC_DSENTRY_MSTATE_ALIVE) { + ret = (old_state == MAGIC_DSENTRY_MSTATE_DEAD + || old_state == MAGIC_DSENTRY_MSTATE_FREED) + ? MAGIC_EBADMSTATE : MAGIC_EBADENT; + break; + } + MAGIC_DSENTRY_TO_SENTRY(dsentry)->id = MAGIC_FAA(&_magic_sentries_next_id, 1); + assert(_magic_sentries_next_id < MAGIC_ID_MAX); + if (!MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(dsentry), MAGIC_STATE_MEMBLOCK)) { + num_dead_dsentries = MAGIC_FAA(&magic_num_dead_dsentries, 1) + 1; + size_dead_dsentries = MAGIC_FAA(&magic_size_dead_dsentries, size) + size; + MAGIC_MEM_PRINTF("magic_update_dsentry_state: ++magic_num_dead_dsentries (num=%d, size=%d)\n", num_dead_dsentries, size_dead_dsentries); + if(!magic_ignore_dead_dsentries + && MAGIC_DEAD_DSENTRIES_NEED_FREEING()) { + magic_free_dead_dsentries(); + } + } + break; + default: + ret = MAGIC_EINVAL; + break; + } + + return ret; +} + +/*===========================================================================* + * magic_free_dsentry * + *===========================================================================*/ +PRIVATE int magic_free_dsentry(struct _magic_dsentry *dsentry) +{ + int ret = 0; + struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry); + int region = MAGIC_STATE_REGION(sentry); + void *ptr = MAGIC_PTR_FROM_DSENTRY(dsentry); + size_t page_size, size; + void *data_ptr, *aligned_ptr; + int from_wrapper = MAGIC_MEM_WRAPPER_IS_ACTIVE(); + assert(dsentry->magic_number == MAGIC_DSENTRY_MNUM_NULL); + + if (!from_wrapper) { + MAGIC_MEM_WRAPPER_BEGIN(); + } + + if (magic_mem_heap_free_cb) { + ret = magic_mem_heap_free_cb(dsentry); + if (ret != MAGIC_ENOENT) + return ret; + + /* + * If the callback returned MAGIC_ENOENT, fallback to + * the default behavior. + */ + ret = 0; + } + + /* A MAP_SHARED region will have both MAGIC_STATE_MAP and MAGIC_STATE_SHM. */ + if (region == (MAGIC_STATE_MAP | MAGIC_STATE_SHM)) + region = MAGIC_STATE_MAP; + switch (region) { + case MAGIC_STATE_HEAP: + MAGIC_MEM_DEBUG_FREE(ptr); + free(ptr); + break; + case MAGIC_STATE_MAP: + case MAGIC_STATE_SHM: + page_size = MAGIC_PAGE_SIZE; + size = MAGIC_DSENTRY_TO_SENTRY(dsentry)->type->size; + data_ptr = MAGIC_PTR_TO_DATA(ptr); + aligned_ptr = ((char *)data_ptr) - page_size; + + if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_DETACHED)) { + size_t padding_size = (size_t) dsentry->ext; + MAGIC_MEM_DEBUG_FREE(ptr); + ret = munmap(((char *)aligned_ptr) - padding_size, page_size + size + padding_size); + } + else { +#ifndef __MINIX + if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_SHM)) + ret = shmdt(data_ptr); + else +#endif + ret = munmap(data_ptr, size); + MAGIC_MEM_DEBUG_FREE(ptr); + munmap(aligned_ptr, page_size); + } + if (ret != 0) { + ret = MAGIC_EBADENT; + } + break; + default: + ret = MAGIC_EBADENT; + break; + } + if (!from_wrapper) { + MAGIC_MEM_WRAPPER_END(); + } + + return ret; +} + +/*===========================================================================* + * magic_free_dead_dsentries * + *===========================================================================*/ +PUBLIC void magic_free_dead_dsentries() +{ + struct _magic_dsentry *prev_dsentry, *dsentry, *next_first_dsentry, *skipped_dsentry; + struct _magic_sentry *sentry; + unsigned long num_dead_dsentries; + int dead_dsentries_left; + int ret; + + MAGIC_DSENTRY_LOCK(); + + skipped_dsentry = NULL; + num_dead_dsentries = magic_num_dead_dsentries; + next_first_dsentry = _magic_first_dsentry; + if (next_first_dsentry) { + /* if the first dsentry is dead, skip it to eliminate contention on the list head */ + if (next_first_dsentry->magic_state == MAGIC_DSENTRY_MSTATE_DEAD){ + num_dead_dsentries--; + } + } + + if(!next_first_dsentry || num_dead_dsentries == 0) { + MAGIC_DSENTRY_UNLOCK(); + return; + } + + MAGIC_MEM_PRINTF("magic_free_dead_dsentries: Freeing %d dead dsentries...\n", num_dead_dsentries); + + /* Eliminate the dead dsentries but always skip the first one to eliminate contention on the head. */ + do { + dead_dsentries_left = 0; + MAGIC_DSENTRY_ITER(next_first_dsentry->next, prev_dsentry, dsentry, sentry, + /* normal dsentry to be freed */ + if ((dsentry->magic_state != MAGIC_DSENTRY_MSTATE_DEAD) || + (magic_update_dsentry_state(dsentry, MAGIC_DSENTRY_MSTATE_FREED) < 0)) { + next_first_dsentry = dsentry; + } else { + magic_destroy_dsentry(dsentry, prev_dsentry); + ret = magic_free_dsentry(dsentry); + if(ret != 0) { + _magic_printf("Warning: magic_free_dsentry failed with return code %d for: ", ret); + MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR); + MAGIC_MEM_PRINTF("\n"); + } + num_dead_dsentries--; + dead_dsentries_left = 1; + break; + } + ); + } while(dead_dsentries_left && num_dead_dsentries > 0); + assert(num_dead_dsentries == 0); + + MAGIC_DSENTRY_UNLOCK(); +} + +/*===========================================================================* + * magic_destroy_dsentry * + *===========================================================================*/ +PUBLIC void magic_destroy_dsentry(struct _magic_dsentry *dsentry, + struct _magic_dsentry *prev_dsentry) +{ + struct _magic_dsentry *next_dsentry, *next_mempool_dsentry, *prev_mempool_dsentry = NULL; + int dsentry_destroyed, mempool_dsentry_destroyed; + + if(magic_destroy_dsentry_ext_cb && MAGIC_DSENTRY_HAS_EXT(dsentry)) { + magic_destroy_dsentry_ext_cb(dsentry); + } + if (MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(dsentry), MAGIC_STATE_MEMPOOL)) { + do { + if(!prev_mempool_dsentry) { + if(MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) != MAGIC_DSENTRY_NEXT_MEMPOOL(_magic_first_mempool_dsentry)) { + prev_mempool_dsentry = magic_mempool_dsentry_prev_lookup(dsentry); + assert(prev_mempool_dsentry != (struct _magic_dsentry *) MAGIC_ENOPTR && "Dsentry not found!"); + } + } + if(prev_mempool_dsentry) { + MAGIC_DSENTRY_NEXT_MEMPOOL(prev_mempool_dsentry) = MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry); + mempool_dsentry_destroyed = 1; + } + else { + /* Remove the first dsentry atomically. */ + next_mempool_dsentry = MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry); + mempool_dsentry_destroyed = (MAGIC_CAS(&_magic_first_mempool_dsentry, + dsentry, next_mempool_dsentry) == dsentry); + } + } while(!mempool_dsentry_destroyed); + MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) = NULL; + } + do { +#if MAGIC_DSENTRY_ALLOW_PREV + prev_dsentry = MAGIC_DSENTRY_PREV(dsentry); +#else + if(!prev_dsentry) { + if(MAGIC_DSENTRY_NEXT(dsentry) != MAGIC_DSENTRY_NEXT(_magic_first_dsentry)) { + prev_dsentry = magic_dsentry_prev_lookup(dsentry); + assert(prev_dsentry != (struct _magic_dsentry *) MAGIC_ENOPTR && "Dsentry not found!"); + } + } +#endif + + if(prev_dsentry) { + MAGIC_DSENTRY_NEXT(prev_dsentry) = MAGIC_DSENTRY_NEXT(dsentry); + dsentry_destroyed = 1; + } + else { + /* Remove the first dsentry atomically. */ + next_dsentry = MAGIC_DSENTRY_NEXT(dsentry); + dsentry_destroyed = (MAGIC_CAS(&_magic_first_dsentry, + dsentry, next_dsentry) == dsentry); + } + } while(!dsentry_destroyed); + +#if MAGIC_DSENTRY_ALLOW_PREV + next_dsentry = MAGIC_DSENTRY_NEXT(dsentry); + if(next_dsentry) { + MAGIC_DSENTRY_PREV(next_dsentry) = MAGIC_DSENTRY_PREV(dsentry); + } + MAGIC_DSENTRY_PREV(dsentry) = NULL; +#endif + + dsentry->magic_number = MAGIC_DSENTRY_MNUM_NULL; + MAGIC_DSENTRY_NEXT(dsentry) = NULL; +} + +/*===========================================================================* + * magic_destroy_obdsentry_by_addr * + *===========================================================================*/ +PUBLIC int magic_destroy_obdsentry_by_addr(void *data_ptr) +{ + struct _magic_dsentry _magic_dsentry_buff; + struct _magic_sentry *sentry; + struct _magic_dsentry *dsentry; + struct _magic_obdsentry *obdsentry; + int obflags = (MAGIC_STATE_DYNAMIC|MAGIC_STATE_OUT_OF_BAND); + + MAGIC_MEM_WRAPPER_LBEGIN(); + + /* Lookup the obdsentry. */ + sentry = magic_sentry_lookup_by_addr(data_ptr, &_magic_dsentry_buff); + if(!sentry || ((sentry->flags & obflags) != obflags)) { + MAGIC_MEM_WRAPPER_LEND(); + return MAGIC_EINVAL; + } + dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry); + obdsentry = MAGIC_OBDSENTRY_FROM_DSENTRY(dsentry); + + /* Destroy it and free obdsentry slot. */ + magic_destroy_dsentry(dsentry, NULL); + MAGIC_OBDSENTRY_FREE(obdsentry); + + MAGIC_MEM_WRAPPER_LEND(); + + return 0; +} + +/*===========================================================================* + * magic_destroy_dsentry_set_ext_cb * + *===========================================================================*/ +PUBLIC void magic_destroy_dsentry_set_ext_cb(const magic_dsentry_cb_t cb) +{ + magic_destroy_dsentry_ext_cb = cb; +} + +/*===========================================================================* + * magic_update_dsentry * + *===========================================================================*/ +PUBLIC int magic_update_dsentry(void* addr, struct _magic_type *type) +{ + struct _magic_dsentry *prev_dsentry, *dsentry; + struct _magic_sentry* sentry; + size_t size, type_size; + int is_varsized = 0; + int num_vsa_elements = 0; + + MAGIC_DSENTRY_LOCK(); + MAGIC_DSENTRY_ALIVE_BLOCK_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry, + if(sentry->address == addr) { + size = sentry->type->size; + type_size = type->size; + + /* Catch variable-sized struct allocation. */ + if(magic_type_alloc_needs_varsized_array(type, size, &num_vsa_elements)) { + is_varsized = 1; + } + + if(size % type_size != 0 && !is_varsized) { + return MAGIC_EBADENT; + } + if(size == type_size && !is_varsized) { + sentry->type = type; + } + else { + struct _magic_type *array_type = &(dsentry->type); + MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(array_type, type, + MAGIC_DSENTRY_TO_TYPE_ARR(dsentry), size, num_vsa_elements); + array_type->id = MAGIC_FAA(&_magic_types_next_id, 1); + assert(_magic_types_next_id < MAGIC_ID_MAX); + sentry->type = array_type; + } + return 0; + } + ); + MAGIC_DSENTRY_UNLOCK(); + + return MAGIC_ENOENT; +} + +/*===========================================================================* + * magic_stack_init * + *===========================================================================*/ +PUBLIC void magic_stack_init() +{ + struct _magic_obdsentry *obdsentry; + char **ptr; + size_t size; + void *initial_stack_bottom, *initial_stack_top; + unsigned long* word_ptr; + int argc; + char **argv; + + assert(!_magic_first_stack_dsentry && !_magic_last_stack_dsentry); + + /* Find initial stack bottom and top, this should be portable enough */ + for (ptr = environ ; *ptr ; ptr++); + if (ptr == environ){ + /* the environment is empty, and ptr still points to environ. + * decrement ptr twice: once to point at the argv terminator, + * and once to point to point at the last argument, which will be the stack bottom + */ + ptr -= 2; + } else { + /* environment is not empty. decrement the pointer, + * because the for loop walked past the last env variable pointer. + */ + ptr--; + } + + if (*ptr) { + initial_stack_bottom = *ptr+strlen(*ptr)+1; + word_ptr = (unsigned long*) environ; + word_ptr--; + assert(*word_ptr == 0); /* argv terminator */ + word_ptr--; + argc = 0; + while(*word_ptr != (unsigned long) argc) { + argc++; + word_ptr--; + } + argv = (char**) (word_ptr+1); + initial_stack_top = argv; + } else { + /* Environ and argv empty?. Resort to defaults. */ + initial_stack_top = ptr; + initial_stack_bottom = environ; + } + size = (size_t)initial_stack_bottom - (size_t)initial_stack_top + 1; + + /* Create the first stack dsentry. */ + obdsentry = magic_create_obdsentry(initial_stack_top, MAGIC_VOID_TYPE, + size, MAGIC_STATE_STACK, MAGIC_ALLOC_INITIAL_STACK_NAME, NULL); + assert(obdsentry); + _magic_first_stack_dsentry = _magic_last_stack_dsentry = MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry); +} + +/*===========================================================================* + * magic_stack_dsentries_create * + *===========================================================================*/ +PUBLIC void magic_stack_dsentries_create( + struct _magic_dsentry **prev_last_stack_dsentry, int num_dsentries, + /* struct _magic_dsentry *dsentry, struct _magic_type *type, void* data_ptr, char* function_name, char* name, */ ...) +{ + int i; + struct _magic_dsentry *dsentry; + struct _magic_type *type; + void* data_ptr; + char* function_name; + char* name; + char *min_data_ptr = NULL, *max_data_ptr = NULL; + va_list va; + + assert(num_dsentries > 0); + + MAGIC_DSENTRY_LOCK(); + assert(_magic_first_stack_dsentry && "First stack dsentry not found!"); + va_start(va, num_dsentries); + *prev_last_stack_dsentry = _magic_last_stack_dsentry; + for (i = 0 ; i < num_dsentries ; i++) { + dsentry = va_arg(va, struct _magic_dsentry *); + type = va_arg(va, struct _magic_type *); + data_ptr = va_arg(va, void *); + function_name = va_arg(va, char *); + name = va_arg(va, char *); + if (i == num_dsentries - 1) { + /* Return address. */ + int *value_set = (void*) type; + data_ptr = MAGIC_FRAMEADDR_TO_RETADDR_PTR(data_ptr); + type = &(dsentry->type); + magic_create_dsentry(dsentry, data_ptr, MAGIC_VOID_TYPE, MAGIC_VOID_TYPE->size, + MAGIC_STATE_STACK | MAGIC_STATE_CONSTANT | MAGIC_STATE_ADDR_NOT_TAKEN, + name, function_name); + memcpy(type, &magic_default_ret_addr_type, sizeof(struct _magic_type)); + type->contained_types = MAGIC_DSENTRY_TO_TYPE_ARR(dsentry); + type->contained_types[0] = MAGIC_VOID_TYPE; + type->value_set = value_set; + value_set[0] = 1; + value_set[1] = *((int *)data_ptr); + + /* Safe to override the type non-atomically. + * The new type is only more restrictive, and nobody could + * have touched this stack dsentry in the meantime. + */ + MAGIC_DSENTRY_TO_SENTRY(dsentry)->type = type; + } else { + /* Local variable. */ + magic_create_dsentry(dsentry, data_ptr, type, type->size, + MAGIC_STATE_STACK, name, function_name); + if (!min_data_ptr || min_data_ptr > (char *) data_ptr) { + min_data_ptr = (char *) data_ptr; + } + if (!max_data_ptr || max_data_ptr < (char *) data_ptr) { + max_data_ptr = (char *) data_ptr; + } + } + } + +#if MAGIC_FORCE_DYN_MEM_ZERO_INIT + if (min_data_ptr && max_data_ptr) { + memset(min_data_ptr, 0, max_data_ptr - min_data_ptr + 1); + } +#endif + + _magic_last_stack_dsentry = dsentry; + MAGIC_DSENTRY_UNLOCK(); + + va_end(va); +} + +/*===========================================================================* + * magic_stack_dsentries_destroy * + *===========================================================================*/ +PUBLIC void magic_stack_dsentries_destroy( + struct _magic_dsentry **prev_last_stack_dsentry, int num_dsentries, + /* struct _magic_dsentry *dsentry, */ ...) +{ + int i; + struct _magic_dsentry *dsentry; + va_list va; + + assert(num_dsentries > 0); + + MAGIC_MEM_WRAPPER_LBEGIN(); + + va_start(va, num_dsentries); + _magic_last_stack_dsentry = *prev_last_stack_dsentry; + for (i = 0 ; i < num_dsentries ; i++) { + dsentry = va_arg(va, struct _magic_dsentry *); + magic_destroy_dsentry(dsentry, NULL); + } + va_end(va); + + MAGIC_MEM_WRAPPER_LEND(); +} + +/*===========================================================================* + * magic_create_dfunction * + *===========================================================================*/ +PUBLIC int magic_create_dfunction(struct _magic_dfunction *dfunction, + void *data_ptr, struct _magic_type *type, int flags, + char *name, char *parent_name) +{ + struct _magic_function *function = MAGIC_DFUNCTION_TO_FUNCTION(dfunction); + + if(!type) { + type = MAGIC_VOID_TYPE; + } + + memcpy(dfunction, &magic_default_dfunction, sizeof(struct _magic_dfunction)); + + assert(!(type->flags & MAGIC_TYPE_DYNAMIC) && "bad type!"); + + function->type = type; + function->flags |= flags; + function->address = data_ptr; + if(name) { + function->name = name; + } + if(parent_name) { + dfunction->parent_name = parent_name; + } + function->id = MAGIC_FAA(&_magic_functions_next_id, 1); + assert(_magic_functions_next_id < MAGIC_ID_MAX); + + if(_magic_first_dfunction) { + assert(_magic_last_dfunction); + MAGIC_DFUNCTION_NEXT(_magic_last_dfunction) = dfunction; + } + else { + assert(!_magic_last_dfunction); + assert(_magic_dfunctions_num == 0); + _magic_first_dfunction = dfunction; + } + MAGIC_DFUNCTION_PREV(dfunction) = _magic_last_dfunction; + MAGIC_DFUNCTION_NEXT(dfunction) = NULL; + _magic_last_dfunction = dfunction; + _magic_dfunctions_num++; + + assert(magic_check_dfunction(dfunction, 0) && "Bad magic dfunction created!"); + magic_update_dfunction_ranges = 1; + + return 0; +} + +/*===========================================================================* + * magic_destroy_dfunction * + *===========================================================================*/ +PUBLIC void magic_destroy_dfunction(struct _magic_dfunction *dfunction) +{ + dfunction->magic_number = MAGIC_DFUNCTION_MNUM_NULL; + if(MAGIC_DFUNCTION_HAS_NEXT(dfunction)) { + MAGIC_DFUNCTION_PREV(MAGIC_DFUNCTION_NEXT(dfunction)) = MAGIC_DFUNCTION_PREV(dfunction); + } + else { + _magic_last_dfunction = MAGIC_DFUNCTION_PREV(dfunction); + } + if(MAGIC_DFUNCTION_HAS_PREV(dfunction)) { + MAGIC_DFUNCTION_NEXT(MAGIC_DFUNCTION_PREV(dfunction)) = MAGIC_DFUNCTION_NEXT(dfunction); + } + else { + _magic_first_dfunction = MAGIC_DFUNCTION_NEXT(dfunction); + } + MAGIC_DFUNCTION_NEXT(dfunction) = NULL; + MAGIC_DFUNCTION_PREV(dfunction) = NULL; + _magic_dfunctions_num--; + if(_magic_dfunctions_num == 0) { + assert(!_magic_first_dfunction && !_magic_last_dfunction); + } + else { + assert(_magic_first_dfunction && _magic_last_dfunction); + } +} + +/*===========================================================================* + * magic_create_sodesc * + *===========================================================================*/ +PUBLIC int magic_create_sodesc(struct _magic_sodesc *sodesc) +{ + if(_magic_first_sodesc) { + assert(_magic_last_sodesc); + MAGIC_SODESC_NEXT(_magic_last_sodesc) = sodesc; + } + else { + assert(!_magic_last_sodesc); + assert(_magic_sodescs_num == 0); + _magic_first_sodesc = sodesc; + } + MAGIC_SODESC_PREV(sodesc) = _magic_last_sodesc; + MAGIC_SODESC_NEXT(sodesc) = NULL; + _magic_last_sodesc = sodesc; + _magic_sodescs_num++; + + return 0; +} + +/*===========================================================================* + * magic_destroy_sodesc * + *===========================================================================*/ +PUBLIC int magic_destroy_sodesc(struct _magic_sodesc *sodesc) +{ + /* + * NB!: This function requires the calling thread to already + * hold the DSENTRY and DFUNCTION locks. + */ + int ret; + const char *name; + struct _magic_dsentry *prev_dsentry, *dsentry, *last_dsentry; + struct _magic_sentry *sentry; + struct _magic_dfunction *dfunction, *last_dfunction; + + /* + * Time to destroy all the dsentries and dfunctions + * linked to the descriptor. + */ + name = sodesc->lib.name; + last_dsentry = NULL; + MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, + dsentry, sentry, + if (last_dsentry) + magic_destroy_dsentry(last_dsentry, NULL); + last_dsentry = dsentry->parent_name == name ? dsentry : NULL; + ); + if (last_dsentry) + magic_destroy_dsentry(last_dsentry, NULL); + last_dfunction = NULL; + MAGIC_DFUNCTION_ITER(_magic_first_dfunction, dfunction, + if (last_dfunction) + magic_destroy_dfunction(last_dfunction); + last_dfunction = dfunction->parent_name == name ? dfunction : NULL; + ); + if(last_dfunction) magic_destroy_dfunction(last_dfunction); + + /* Now get rid of the descriptor. */ + if (MAGIC_SODESC_HAS_NEXT(sodesc)) { + MAGIC_SODESC_PREV(MAGIC_SODESC_NEXT(sodesc)) = + MAGIC_SODESC_PREV(sodesc); + } + else { + _magic_last_sodesc = MAGIC_SODESC_PREV(sodesc); + } + if (MAGIC_SODESC_HAS_PREV(sodesc)) { + MAGIC_SODESC_NEXT(MAGIC_SODESC_PREV(sodesc)) = + MAGIC_SODESC_NEXT(sodesc); + } + else { + _magic_first_sodesc = MAGIC_SODESC_NEXT(sodesc); + } + MAGIC_SODESC_NEXT(sodesc) = NULL; + MAGIC_SODESC_PREV(sodesc) = NULL; + _magic_sodescs_num--; + if (_magic_sodescs_num == 0) { + assert(!_magic_first_sodesc && !_magic_last_sodesc); + } + else { + assert(_magic_first_sodesc && _magic_last_sodesc); + } + + /* + * Unmap the memory area that contained the dsentries and dfunctions + * of this descriptor. + */ + ret = munmap(sodesc->lib.alloc_address, sodesc->lib.alloc_size); + assert(ret == 0 && "Unable to unmap SODESC memory segment!"); + + return 0; +} + +/*===========================================================================* + * magic_create_dsodesc * + *===========================================================================*/ +PUBLIC int magic_create_dsodesc(struct _magic_dsodesc *dsodesc) +{ + /* + * NB!: This function requires the calling thread to already + * hold the DSODESC lock. + */ + if (_magic_first_dsodesc) { + assert(_magic_last_dsodesc); + MAGIC_DSODESC_NEXT(_magic_last_dsodesc) = dsodesc; + } + else { + assert(!_magic_last_dsodesc); + assert(_magic_dsodescs_num == 0); + _magic_first_dsodesc = dsodesc; + } + MAGIC_DSODESC_PREV(dsodesc) = _magic_last_dsodesc; + MAGIC_DSODESC_NEXT(dsodesc) = NULL; + _magic_last_dsodesc = dsodesc; + _magic_dsodescs_num++; + + return 0; +} + +/*===========================================================================* + * magic_destroy_dsodesc * + *===========================================================================*/ +PUBLIC int magic_destroy_dsodesc(struct _magic_dsodesc *dsodesc) +{ + /* + * NB!: This function requires the calling thread to already + * hold the DSENTRY, DFUNCTION and DSODESC locks. + */ + int ret; + const char *name; + struct _magic_dsentry *prev_dsentry, *dsentry, *last_dsentry; + struct _magic_sentry *sentry; + struct _magic_dfunction *dfunction, *last_dfunction; + + dsodesc->ref_count--; + /* Don't destroy the DSO descriptor quite yet, we still have references. */ + if (dsodesc->ref_count > 0) { + return dsodesc->ref_count; + } + + /* + * Time to destroy all the dsentries and dfunctions + * linked to the descriptor. + */ + name = dsodesc->lib.name; + last_dsentry = NULL; + MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, + dsentry, sentry, + if (last_dsentry) + magic_destroy_dsentry(last_dsentry, NULL); + last_dsentry = dsentry->parent_name == name ? dsentry : NULL; + ); + if (last_dsentry) + magic_destroy_dsentry(last_dsentry, NULL); + last_dfunction = NULL; + MAGIC_DFUNCTION_ITER(_magic_first_dfunction, dfunction, + if (last_dfunction) + magic_destroy_dfunction(last_dfunction); + last_dfunction = dfunction->parent_name == name ? dfunction : NULL; + ); + if (last_dfunction) + magic_destroy_dfunction(last_dfunction); + + /* Now get rid of the descriptor. */ + if (MAGIC_DSODESC_HAS_NEXT(dsodesc)) { + MAGIC_DSODESC_PREV(MAGIC_DSODESC_NEXT(dsodesc)) = + MAGIC_DSODESC_PREV(dsodesc); + } + else { + _magic_last_dsodesc = MAGIC_DSODESC_PREV(dsodesc); + } + if (MAGIC_DSODESC_HAS_PREV(dsodesc)) { + MAGIC_DSODESC_NEXT(MAGIC_DSODESC_PREV(dsodesc)) = + MAGIC_DSODESC_NEXT(dsodesc); + } + else { + _magic_first_dsodesc = MAGIC_DSODESC_NEXT(dsodesc); + } + MAGIC_DSODESC_NEXT(dsodesc) = NULL; + MAGIC_DSODESC_PREV(dsodesc) = NULL; + _magic_dsodescs_num--; + if (_magic_dsodescs_num == 0) { + assert(!_magic_first_dsodesc && !_magic_last_dsodesc); + } + else { + assert(_magic_first_dsodesc && _magic_last_dsodesc); + } + + /* + * Unmap the memory area that contained the dsentries and dfunctions + * of this descriptor. + */ + ret = munmap(dsodesc->lib.alloc_address, dsodesc->lib.alloc_size); + assert(ret == 0 && "Unable to unmap DSODESC memory segment!"); + + return 0; /* no more references, descriptor is gone. */ +} + +/*===========================================================================* + * magic_alloc * + *===========================================================================*/ +PUBLIC void *magic_alloc(__MA_ARGS__ void *ptr, size_t size, int flags) +{ + int ret; + void *data_ptr; + struct _magic_dsentry *dsentry; + + if(ptr == NULL) { + return NULL; + } + data_ptr = MAGIC_PTR_TO_DATA(ptr); + dsentry = MAGIC_PTR_TO_DSENTRY(ptr); + /* Catch pool allocations and update the name & flags */ + if (MAGIC_MEMPOOL_MGMT_IS_ACTIVE() && !(flags & MAGIC_STATE_MEMBLOCK)) { + flags |= MAGIC_STATE_MEMPOOL; + name = MAGIC_MEMPOOL_GET_NAME(); + } + ret = magic_create_dsentry(dsentry, data_ptr, type, size, flags, name, parent_name); + MAGIC_MEM_PRINTF("magic_alloc: ret = magic_create_dsentry(dsentry, data_ptr, type, size, flags, NULL, NULL) <-> %d = magic_create_dsentry(0x%08x, 0x%08x, 0x%08x, %d, 0x%08x, NULL, NULL)\n", ret, (unsigned) dsentry, (unsigned) data_ptr, type, size, flags); + if(ret < 0) { + return MAGIC_MEM_FAILED; + } + + /* this way we skip the memory pool blocks -they are not real allocations and should not be logged */ + if (!(flags & MAGIC_STATE_MEMBLOCK)) { + MAGIC_MEM_DEBUG_ALLOC(ptr, (MAGIC_SIZE_TO_REAL(size))); + } + +#if DEBUG + MAGIC_MEM_PRINTF("magic_alloc: magic_create_dsentry created sentry: "); + MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR); + MAGIC_MEM_PRINTF("\n"); +#endif + + MAGIC_MEM_PRINTF("magic_alloc: return 0x%08x\n", (unsigned) data_ptr); + + return data_ptr; +} + +/*===========================================================================* + * magic_malloc_positioned * + *===========================================================================*/ +PUBLIC void *magic_malloc_positioned(__MA_ARGS__ size_t size, void *ptr) +{ + void *data_ptr; + int dsentry_flags = MAGIC_STATE_HEAP; + +#if MAGIC_FORCE_DYN_MEM_ZERO_INIT + assert(!_magic_vars->fake_malloc); + do { + return magic_calloc(__MA_VALUES__ size, 1); + } while(0); +#endif + + MAGIC_MEM_WRAPPER_BEGIN(); + + if(size > 0) { + if (!ptr || !_magic_vars->fake_malloc) { + /* + * Check the external callback first. + */ + if (magic_mem_heap_alloc_cb) + ptr = magic_mem_heap_alloc_cb(MAGIC_SIZE_TO_REAL(size) + magic_asr_get_padding_size(MAGIC_STATE_HEAP), name, parent_name); + + if (!ptr) + ptr = malloc(MAGIC_SIZE_TO_REAL(size) + magic_asr_get_padding_size(MAGIC_STATE_HEAP)); + MAGIC_MEM_PRINTF("magic_malloc: ptr = malloc(size) <-> 0x%08x = malloc(%d)\n", (unsigned) ptr, MAGIC_SIZE_TO_REAL(size)); + } + data_ptr = magic_alloc(__MA_VALUES__ ptr, size, dsentry_flags); + if (data_ptr == MAGIC_MEM_FAILED) { + /* + * XXX: This doesn't seem likely to happen. However, if it does, + * we need to distinguish between regular malloc() memory + * and super-objects. See llvm/shared/libst/include/heap.h for + * more information. + */ + free(ptr); + data_ptr = NULL; + errno = ENOMEM; + } + magic_heap_end = ((char *)sbrk(0)) - 1; + } + else { + data_ptr = NULL; + } + + MAGIC_MEM_WRAPPER_END(); + + return data_ptr; +} + +/*===========================================================================* + * magic_malloc * + *===========================================================================*/ +PUBLIC void *magic_malloc(__MA_ARGS__ size_t size) +{ + return magic_malloc_positioned(__MA_VALUES__ size, NULL); +} + +/*===========================================================================* + * magic_calloc * + *===========================================================================*/ +PUBLIC void *magic_calloc(__MA_ARGS__ size_t nmemb, size_t size) +{ + void *ptr = NULL, *data_ptr; + size_t real_size; + int dsentry_flags = MAGIC_STATE_HEAP; + + MAGIC_MEM_WRAPPER_BEGIN(); + + if(size > 0) { + real_size = MAGIC_SIZE_TO_REAL(size*nmemb); + /* + * Check the external callback first. + */ + if (magic_mem_heap_alloc_cb) + ptr = magic_mem_heap_alloc_cb(real_size + magic_asr_get_padding_size(MAGIC_STATE_HEAP), name, parent_name); + + if (!ptr) + ptr = calloc(real_size + magic_asr_get_padding_size(MAGIC_STATE_HEAP), 1); + MAGIC_MEM_PRINTF("magic_calloc: ptr = calloc(nmemb, size) <-> 0x%08x = calloc(%d, %d)\n", (unsigned) ptr, nmemb, real_size); + data_ptr = magic_alloc(__MA_VALUES__ ptr, size*nmemb, dsentry_flags); + if(data_ptr == MAGIC_MEM_FAILED) { + /* + * XXX: This doesn't seem likely to happen. However, if it does, + * we need to distinguish between regular malloc() memory + * and super-objects. See llvm/shared/libst/include/heap.h for + * more information. + */ + free(ptr); + data_ptr = NULL; + errno = ENOMEM; + } + magic_heap_end = ((char*)sbrk(0))-1; + } + else { + data_ptr = NULL; + } + + MAGIC_MEM_WRAPPER_END(); + + return data_ptr; +} + +/*===========================================================================* + * magic_free * + *===========================================================================*/ +PUBLIC void magic_free(__MD_ARGS__ void *data_ptr) +{ + void *ptr; + int ret; + + MAGIC_MEM_WRAPPER_BEGIN(); + + if(data_ptr) { + ptr = MAGIC_PTR_FROM_DATA(data_ptr); + + /* Check for legitimate non-indexed chunks of memory and skip. */ + if((!magic_libcommon_active || !MAGIC_USE_DYN_MEM_WRAPPERS) + && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr))) { + MAGIC_MEM_WRAPPER_END(); + free(data_ptr); + return; + } + + MAGIC_MEM_PRINTF("magic_free: magic_free(0x%08x) / free(0x%08x)\n", (unsigned) data_ptr, (unsigned) ptr); + assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_HEAP) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?"); + + if(magic_allow_dead_dsentries) { + ret = magic_update_dsentry_state(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_DSENTRY_MSTATE_DEAD); + assert(ret == 0 && "Bad free!"); + } + else { + MAGIC_DSENTRY_LOCK(); + magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), NULL); + ret = magic_free_dsentry(MAGIC_PTR_TO_DSENTRY(ptr)); + assert(ret == 0 && "Bad free!"); + MAGIC_DSENTRY_UNLOCK(); + } + } + + MAGIC_MEM_WRAPPER_END(); +} + +/*===========================================================================* + * magic_realloc * + *===========================================================================*/ +PUBLIC void *magic_realloc(__MA_ARGS__ void *data_ptr, size_t size) +{ + void *ptr, *new_ptr, *new_data_ptr; + size_t old_size; + + if(!data_ptr) { + return magic_malloc(__MA_VALUES__ size); + } + if(size == 0) { + magic_free(__MD_VALUES_DEFAULT__ data_ptr); + return NULL; + } + + ptr = MAGIC_PTR_FROM_DATA(data_ptr); + new_data_ptr = magic_malloc(__MA_VALUES__ size); + if(!new_data_ptr) { + return NULL; + } + new_ptr = MAGIC_PTR_FROM_DATA(new_data_ptr); + assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_HEAP) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?"); + MAGIC_MEM_PRINTF("magic_realloc: ptr = realloc(ptr, size) <-> 0x%08x = realloc(0x%08x, %d)\n", (unsigned) new_ptr, (unsigned) ptr, MAGIC_SIZE_TO_REAL(size)); + + old_size = MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr))->type->size; + memcpy(new_data_ptr, data_ptr, old_size < size ? old_size : size); + magic_free(__MD_VALUES_DEFAULT__ data_ptr); + + return new_data_ptr; +} + +/*===========================================================================* + * magic_posix_memalign * + *===========================================================================*/ +PUBLIC int magic_posix_memalign(__MA_ARGS__ void **memptr, size_t alignment, size_t size) +{ + int ret = 0; + void *ptr = NULL, *data_ptr; + int dsentry_flags = MAGIC_STATE_HEAP; + + MAGIC_MEM_WRAPPER_BEGIN(); + + if(size > 0) { + /* + * Check the external callback first. + */ + if (magic_mem_heap_alloc_cb) + ptr = magic_mem_heap_alloc_cb(MAGIC_SIZE_TO_REAL(size), name, parent_name); + + if (!ptr) + ret = posix_memalign(&ptr, alignment, MAGIC_SIZE_TO_REAL(size)); + MAGIC_MEM_PRINTF("magic_posix_memalign: ret = posix_memalign(ptr, alignment, size) <-> %d = posix_memalign(%p, %d, %d)\n", ret, ptr, alignment, MAGIC_SIZE_TO_REAL(size)); + if(ret == 0) { + data_ptr = magic_alloc(__MA_VALUES__ ptr, size, dsentry_flags); + if(data_ptr == MAGIC_MEM_FAILED) { + /* + * XXX: This doesn't seem likely to happen. However, if it does, + * we need to distinguish between regular malloc() memory + * and super-objects. See llvm/shared/libst/include/heap.h for + * more information. + */ + free(ptr); + ret = ENOMEM; + } + else { + *memptr = data_ptr; +#if MAGIC_FORCE_DYN_MEM_ZERO_INIT + memset(data_ptr, 0, size); +#endif + } + magic_heap_end = ((char*)sbrk(0))-1; + } + } + else { + ret = EINVAL; + } + + MAGIC_MEM_WRAPPER_END(); + + return ret; +} + +#ifndef __MINIX +/*===========================================================================* + * magic_valloc * + *===========================================================================*/ +PUBLIC void *magic_valloc(__MA_ARGS__ size_t size) +{ + return magic_memalign(__MA_VALUES__ MAGIC_PAGE_SIZE, size); +} + +/*===========================================================================* + * magic_memalign * + *===========================================================================*/ +PUBLIC void *magic_memalign(__MA_ARGS__ size_t boundary, size_t size) +{ + void *ptr; + int ret = magic_posix_memalign(__MA_VALUES__ &ptr, boundary, size); + if(ret != 0) { + return NULL; + } + return ptr; +} + +#endif + +/*===========================================================================* + * magic_mmap_positioned * + *===========================================================================*/ +PUBLIC void *magic_mmap_positioned(__MA_ARGS__ void *start, size_t length, int prot, int flags, + int fd, off_t offset, struct _magic_dsentry *cached_dsentry) +{ + void *ptr, *data_ptr, *aligned_start, *aligned_ptr; + void *new_ptr, *new_start; + int dsentry_flags = MAGIC_STATE_MAP; + size_t alloc_length; + size_t page_size = MAGIC_PAGE_SIZE; + int padding_type, padding_size; + static THREAD_LOCAL int magic_is_first_mmap = 1; + + MAGIC_MEM_WRAPPER_BEGIN(); + + if (flags & MAP_FIXED) { + /* Allow safe overmapping. */ + struct _magic_sentry *sentry = magic_sentry_lookup_by_range(start, NULL); + if (sentry && sentry == magic_sentry_lookup_by_range((char*)start+length-1, NULL)) + return mmap(start, length, prot, flags, fd, offset); + } + assert(!(flags & MAP_FIXED) && "MAP_FIXED may override existing mapping, currently not implemented!"); + if (length > 0) { + if (magic_is_first_mmap) { + magic_is_first_mmap = 0; + padding_type = MAGIC_STATE_MAP | MAGIC_ASR_FLAG_INIT; + } else { + padding_type = MAGIC_STATE_MAP; + } + padding_size = start ? 0 : magic_asr_get_padding_size(padding_type); + + assert(MAGIC_SIZE_TO_REAL(length) <= page_size + length); + aligned_start = start ? ((char *)start) - page_size : NULL; + alloc_length = length + (length % page_size == 0 ? 0 : page_size - (length % page_size)); +#if 0 + if (_magic_vars->do_skip_mmap) { + ptr = cached_dsentry ? ((char *)cached_dsentry) - (padding_size + page_size - MAGIC_SIZE_TO_REAL(0)) : NULL; + } else +#endif + if (!(flags & MAP_ANONYMOUS) && !(flags & MAP_SHARED) && ((prot & magic_mmap_dsentry_header_prot) == magic_mmap_dsentry_header_prot)) { + ptr = mmap(aligned_start, page_size + alloc_length + padding_size, prot, flags, fd, offset); + } + else { + /* Preallocate memory for metadata + data. */ + ptr = mmap(aligned_start, page_size + alloc_length + padding_size, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS | MAP_PRIVATE | (flags & MAP_FIXED), -1, 0); + + /* Remap the data part the way the caller wants us to. */ + if (ptr != MAP_FAILED) { + new_start = ((char *)ptr) + page_size; + new_ptr = mmap(new_start, length, prot, flags | MAP_FIXED, fd, offset); + if (new_ptr == MAP_FAILED) { + munmap(ptr, page_size + alloc_length); + ptr = MAP_FAILED; + } + } + } + aligned_ptr = ptr; + MAGIC_MEM_PRINTF("magic_mmap: ptr = mmap(start, length, prot, flags, fd, offset) <-> 0x%08x = mmap(0x%08x, %d, 0x%08x, 0x%08x, %d, %d)\n", (unsigned) aligned_ptr, aligned_start, page_size + length, prot, flags, fd, offset); + if (ptr != MAP_FAILED) { + ptr = ((char *)ptr) + padding_size + page_size - MAGIC_SIZE_TO_REAL(0); + } + else { + ptr = NULL; + } + if (flags & MAP_SHARED) + dsentry_flags |= MAGIC_STATE_SHM; + data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, dsentry_flags); + if (data_ptr == MAGIC_MEM_FAILED) { + munmap(aligned_ptr, page_size + length); + data_ptr = NULL; + errno = ENOMEM; + } + if (!data_ptr) { + errno = ENOMEM; + data_ptr = MAP_FAILED; + } else { + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = flags; + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = prot; + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->ext = (void *) padding_size; + } + } + else { + data_ptr = MAP_FAILED; + errno = EINVAL; + } + + MAGIC_MEM_WRAPPER_END(); + + return data_ptr; +} + +/*===========================================================================* + * magic_mmap * + *===========================================================================*/ +PUBLIC void *magic_mmap(__MA_ARGS__ void *start, size_t length, int prot, int flags, + int fd, off_t offset) +{ + return magic_mmap_positioned(__MA_VALUES__ start, length, prot, flags, fd, offset, NULL); +} + +/*===========================================================================* + * magic_munmap * + *===========================================================================*/ +PUBLIC int magic_munmap(__MD_ARGS__ void *data_ptr, size_t length) +{ + int ret; + void *ptr, *aligned_ptr; + struct _magic_sentry *sentry; + size_t alloc_length, old_size; + size_t page_size = MAGIC_PAGE_SIZE; + + MAGIC_MEM_WRAPPER_BEGIN(); + + if(data_ptr) { + ptr = MAGIC_PTR_FROM_DATA(data_ptr); + + /* Check for legitimate non-indexed chunks of memory and skip. */ + if((!magic_libcommon_active || !MAGIC_USE_DYN_MEM_WRAPPERS) + && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr))) { + MAGIC_MEM_WRAPPER_END(); + return munmap(data_ptr, length); + } + + sentry = MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr)); + aligned_ptr = ((char*)data_ptr) - page_size; + MAGIC_MEM_PRINTF("magic_munmap: magic_munmap(0x%08x, %d) / unmap(0x%08x, %d)\n", (unsigned) data_ptr, length, (unsigned) aligned_ptr, page_size+length); + assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_MAP) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?"); + old_size = MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr))->type->size; + alloc_length = length + (length % page_size == 0 ? 0 : page_size-(length % page_size)); + + if(alloc_length != old_size) { + assert(alloc_length >= old_size && "Partial unmapping not supported!"); + ret = -1; + errno = EINVAL; + } + else { + if(magic_allow_dead_dsentries) { + ret = magic_update_dsentry_state(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_DSENTRY_MSTATE_DEAD); + assert(ret == 0 && "Bad munmap!"); + } + else { + MAGIC_DSENTRY_LOCK(); + magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), NULL); + ret = magic_free_dsentry(MAGIC_PTR_TO_DSENTRY(ptr)); + assert(ret == 0 && "Bad munmap!"); + MAGIC_DSENTRY_UNLOCK(); + } + } + } + else { + ret = -1; + errno = EINVAL; + } + + MAGIC_MEM_WRAPPER_END(); + + return ret; +} + +/*===========================================================================* + * magic_brk * + *===========================================================================*/ +PUBLIC int magic_brk(__MA_ARGS__ void *addr) +{ + void *ptr; + void *break_addr; + int ret; + + MAGIC_MEM_PRINTF("magic_brk: Warning: somebody calling magic_brk()!"); + MAGIC_MEM_WRAPPER_LBLOCK( break_addr = sbrk(0); ); + if(addr >= break_addr) { + ptr = magic_sbrk(__MA_VALUES__ (char*)addr - (char*)break_addr); + ret = (ptr == (void*) -1 ? -1 : 0); + if(ret == -1) { + errno = ENOMEM; + } + } + else { + magic_free(__MD_VALUES_DEFAULT__ addr); + ret = 0; + } + + return ret; +} + +/*===========================================================================* + * magic_sbrk * + *===========================================================================*/ +PUBLIC void *magic_sbrk(__MA_ARGS__ intptr_t increment) +{ + void *ptr; + + if(increment == 0) { + MAGIC_MEM_WRAPPER_LBLOCK( ptr = sbrk(0); ); + } + else { + MAGIC_MEM_PRINTF("magic_sbrk: Warning: somebody calling magic_sbrk(), resorting to magic_malloc()!"); + ptr = magic_malloc(__MA_VALUES__ increment); + } + + return ptr; +} + +#ifndef __MINIX +/*===========================================================================* + * magic_shmat * + *===========================================================================*/ +PUBLIC void *magic_shmat(__MA_ARGS__ int shmid, const void *shmaddr, int shmflg) +{ + void *ptr, *data_ptr, *aligned_shmaddr, *aligned_ptr; + void *new_ptr, *new_shmaddr; + size_t size; + struct shmid_ds buf; + int ret, flags; + size_t page_size = MAGIC_PAGE_SIZE; + + MAGIC_MEM_WRAPPER_BEGIN(); + + assert(!(shmflg & SHM_REMAP) && "Linux-specific SHM_REMAP not supported!"); + ret = shmctl(shmid, IPC_STAT, &buf); + if (ret == -1) { + MAGIC_MEM_WRAPPER_END(); + return NULL; + } + size = buf.shm_segsz; + if (size > 0) { + assert(size % page_size == 0); + assert(MAGIC_SIZE_TO_REAL(size) <= size + page_size); + if (shmaddr && (shmflg & SHM_RND)) { + unsigned long shmlba = SHMLBA; + shmflg &= ~SHM_RND; + shmaddr = (void *) ((((unsigned long)shmaddr) / shmlba) * shmlba); + } + + /* Preallocate memory for metadata + data. */ + aligned_shmaddr = shmaddr ? ((char *)shmaddr) - page_size : NULL; + flags = MAP_ANONYMOUS | MAP_PRIVATE | (aligned_shmaddr ? MAP_FIXED : 0); + ptr = mmap(aligned_shmaddr, page_size + size, magic_mmap_dsentry_header_prot, flags, -1, 0); + + /* Remap the data part the way the caller wants us to. */ + if (ptr != MAP_FAILED) { + new_shmaddr = ((char *)ptr) + page_size; + munmap(new_shmaddr, size); + new_ptr = shmat(shmid, new_shmaddr, shmflg); + if(new_ptr == (void *) -1) { + munmap(ptr, page_size); + ptr = MAP_FAILED; + } + } + aligned_ptr = ptr; + MAGIC_MEM_PRINTF("magic_shmat: ptr = shmat(shmid, shmaddr, shmflg) <-> 0x%08x = shmat(%d, 0x%08x, 0x%08x)\n", (unsigned) aligned_ptr, shmid, aligned_shmaddr, shmflg); + if (ptr != MAP_FAILED) { + ptr = ((char *)ptr) + page_size - MAGIC_SIZE_TO_REAL(0); + } + else { + ptr = NULL; + } + data_ptr = magic_alloc(__MA_VALUES__ ptr, size, MAGIC_STATE_SHM | MAGIC_STATE_DETACHED); + if (data_ptr == MAGIC_MEM_FAILED) { + munmap(aligned_ptr, page_size); + munmap(new_ptr, size); + data_ptr = (void *) -1; + errno = ENOMEM; + } + else { + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_shmat_flags = shmflg; + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_shmat_shmid = shmid; + } + } + else { + data_ptr = (void *) -1; + errno = EINVAL; + } + + MAGIC_MEM_WRAPPER_END(); + + return data_ptr; +} + +/*===========================================================================* + * magic_shmdt * + *===========================================================================*/ +PUBLIC int magic_shmdt(__MD_ARGS__ const void *data_ptr) +{ + int ret; + void *ptr, *aligned_ptr; + size_t page_size = MAGIC_PAGE_SIZE; + + MAGIC_MEM_WRAPPER_LBEGIN(); + + if (data_ptr) { + ptr = MAGIC_PTR_FROM_DATA(data_ptr); + + /* Check for legitimate non-indexed chunks of memory and skip. */ + if ((!magic_libcommon_active || !MAGIC_USE_DYN_MEM_WRAPPERS) + && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr))) { + MAGIC_MEM_WRAPPER_LEND(); + return shmdt(data_ptr); + } + + aligned_ptr = ((char*)data_ptr) - page_size; + MAGIC_MEM_PRINTF("magic_shmdt: magic_shmdt(0x%08x) / shmdt(0x%08x)\n", (unsigned) data_ptr, (unsigned) aligned_ptr); + assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_SHM) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?"); + ret = shmdt(data_ptr); + if (ret == 0) { + magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), NULL); + munmap(aligned_ptr, page_size); + } + } + else { + ret = -1; + errno = EINVAL; + } + + MAGIC_MEM_WRAPPER_LEND(); + + return ret; +} + +/*===========================================================================* + * magic_mmap64 * + *===========================================================================*/ +PUBLIC void *magic_mmap64(__MA_ARGS__ void *start, size_t length, int prot, int flags, + int fd, off_t pgoffset) +{ + void *ptr, *data_ptr, *aligned_start, *aligned_ptr; + void *new_ptr, *new_start; + int dsentry_flags = MAGIC_STATE_MAP; + size_t alloc_length; + size_t page_size = MAGIC_PAGE_SIZE; + + MAGIC_MEM_WRAPPER_BEGIN(); + + if (flags & MAP_FIXED) { + /* Allow safe overmapping. */ + struct _magic_sentry *sentry = magic_sentry_lookup_by_range(start, NULL); + if (sentry && sentry == magic_sentry_lookup_by_range((char*)start+length-1, NULL)) + return mmap64(start, length, prot, flags, fd, pgoffset); + } + assert(!(flags & MAP_FIXED) && "MAP_FIXED may override existing mapping, currently not implemented!"); + if(length > 0) { + assert(MAGIC_SIZE_TO_REAL(length) <= page_size+length); + aligned_start = start ? ((char*)start) - page_size : NULL; + alloc_length = length + (length % page_size == 0 ? 0 : page_size-(length % page_size)); + if((flags & MAP_ANONYMOUS) && !(flags & MAP_SHARED) && ((prot & magic_mmap_dsentry_header_prot) == magic_mmap_dsentry_header_prot)) { + ptr = mmap64(aligned_start, page_size+length, prot, flags, fd, pgoffset); + } + else { + /* Preallocate memory for metadata + data. */ + ptr = mmap64(aligned_start, page_size+alloc_length, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS|MAP_PRIVATE|(flags & MAP_FIXED), -1, 0); + + /* Remap the data part the way the caller wants us to. */ + if(ptr != MAP_FAILED) { + new_start = ((char*)ptr) + page_size; + new_ptr = mmap64(new_start, length, prot, flags|MAP_FIXED, fd, pgoffset); + if(new_ptr == MAP_FAILED) { + munmap(ptr, page_size+alloc_length); + ptr = MAP_FAILED; + } + } + } + aligned_ptr = ptr; + MAGIC_MEM_PRINTF("magic_mmap64: ptr = mmap64(start, length, prot, flags, fd, pgoffset) <-> 0x%08x = mmap64(0x%08x, %d, 0x%08x, 0x%08x, %d, %d)\n", (unsigned) aligned_ptr, aligned_start, page_size+length, prot, flags, fd, pgoffset); + if(ptr != MAP_FAILED) { + ptr = ((char*)ptr) + page_size - MAGIC_SIZE_TO_REAL(0); + } + else { + ptr = NULL; + } + if (flags & MAP_SHARED) + dsentry_flags |= MAGIC_STATE_SHM; + data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, dsentry_flags); + if(data_ptr == MAGIC_MEM_FAILED) { + munmap(aligned_ptr, page_size+length); + data_ptr = NULL; + errno = ENOMEM; + } + if(!data_ptr) { + errno = ENOMEM; + data_ptr = MAP_FAILED; + } else { + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = flags; + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = prot; + } + } + else { + data_ptr = MAP_FAILED; + errno = EINVAL; + } + + MAGIC_MEM_WRAPPER_END(); + + return data_ptr; +} + +#else +/*===========================================================================* + * magic_vm_map_cacheblock * + *===========================================================================*/ +PUBLIC void *magic_vm_map_cacheblock(__MA_ARGS__ dev_t dev, off_t dev_offset, + ino_t ino, off_t ino_offset, u32_t *flags, int length) +{ + void *ptr, *data_ptr, *aligned_ptr; + int dsentry_flags = MAGIC_STATE_MAP; + size_t alloc_length; + size_t page_size = MAGIC_PAGE_SIZE; + + MAGIC_MEM_WRAPPER_BEGIN(); + + if(length > 0) { + assert(MAGIC_SIZE_TO_REAL(length) <= page_size+length); + alloc_length = length + (length % page_size == 0 ? 0 : page_size-(length % page_size)); + data_ptr = vm_map_cacheblock(dev, dev_offset, ino, ino_offset, flags, length); + if (data_ptr != MAP_FAILED) { + ptr = mmap(data_ptr-page_size, page_size, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + MAGIC_MEM_PRINTF("vm_map_cacheblock: ptr = mmap(start, length, prot, flags, fd, offset) <-> 0x%08x = mmap(0x%08x, %d, 0x%08x, 0x%08x, %d, %d)\n", (unsigned) ptr, data_ptr-page_size, page_size, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + assert(ptr == data_ptr-page_size); /* Ensured by VM. */ + aligned_ptr = ptr; + ptr = ((char*)ptr) + page_size - MAGIC_SIZE_TO_REAL(0); + } + else { + aligned_ptr = NULL; + ptr = NULL; + } + data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, dsentry_flags); + if(data_ptr == MAGIC_MEM_FAILED) { + munmap(aligned_ptr, page_size+length); + data_ptr = NULL; + } + if(!data_ptr) { + data_ptr = MAP_FAILED; + errno = ENOMEM; + } else { + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE; + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = magic_mmap_dsentry_header_prot; + } + } + else { + data_ptr = MAP_FAILED; + errno = EINVAL; + } + + MAGIC_MEM_WRAPPER_END(); + + return data_ptr; +} +#endif + diff --git a/minix/llvm/static/magic/magic_range.c b/minix/llvm/static/magic/magic_range.c new file mode 100644 index 000000000..f65f59aa2 --- /dev/null +++ b/minix/llvm/static/magic/magic_range.c @@ -0,0 +1,321 @@ +#define MAGIC_RANGE_DEBUG MAGIC_DEBUG_SET(0) + +#include + +/*===========================================================================* + * magic_range_is_shlib * + *===========================================================================*/ +PRIVATE int magic_range_is_shlib(void *addr, void **container) +{ + /* + * NB!: This function requires the calling thread to already + * hold the DSODESC lock. + */ + int ret = 0; + struct _magic_sodesc *sodesc; + struct _magic_dsodesc *dsodesc; + + /* First iterate through the SO descriptors. */ + MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc, + /* First check the text range. */ + MAGIC_RANGE_DEBUG_ADDR(addr, sodesc->lib.text_range); + if (MAGIC_ADDR_IS_IN_RANGE(addr, sodesc->lib.text_range)) { + ret |= MAGIC_STATE_TEXT; + goto found_so; + } + /* Next check the data range. */ + MAGIC_RANGE_DEBUG_ADDR(addr, sodesc->lib.data_range); + if (MAGIC_ADDR_IS_IN_RANGE(addr, sodesc->lib.data_range)) { + ret |= MAGIC_STATE_DATA; + goto found_so; + } + ); + + /* Next iterate through the DSO descriptors. */ + MAGIC_SODESC_ITER(_magic_first_dsodesc, dsodesc, + /* First check the text range. */ + MAGIC_RANGE_DEBUG_ADDR(addr, dsodesc->lib.text_range); + if (MAGIC_ADDR_IS_IN_RANGE(addr, dsodesc->lib.text_range)) { + ret |= MAGIC_STATE_TEXT; + goto found_dso; + } + /* Next check the data range. */ + MAGIC_RANGE_DEBUG_ADDR(addr, dsodesc->lib.data_range); + if (MAGIC_ADDR_IS_IN_RANGE(addr, dsodesc->lib.data_range)) { + ret |= MAGIC_STATE_DATA; + goto found_dso; + } + ); + + +out: + return ret; +found_so: + ret |= MAGIC_STATE_LIB | MAGIC_STATE_LIB_SO; + if (container != NULL) + *container = (void *)(sodesc); + goto out; +found_dso: + ret |= MAGIC_STATE_LIB | MAGIC_STATE_LIB_DSO; + if (container != NULL) { + *container = (void *)(dsodesc); + } + goto out; + +} + +/*===========================================================================* + * magic_range_is_data * + *===========================================================================*/ +PRIVATE INLINE int magic_range_is_data(void *addr) +{ + MAGIC_RANGE_DEBUG_ADDR(addr, magic_data_range); + return MAGIC_ADDR_IS_IN_RANGE(addr, magic_data_range) ? MAGIC_STATE_DATA : 0; +} + +/*===========================================================================* + * magic_range_is_text * + *===========================================================================*/ +PRIVATE INLINE int magic_range_is_text(void *addr) +{ + MAGIC_RANGE_DEBUG_ADDR(addr, magic_text_range); + return MAGIC_ADDR_IS_IN_RANGE(addr, magic_text_range) ? MAGIC_STATE_TEXT : 0; +} + +/*===========================================================================* + * magic_range_is_heap * + *===========================================================================*/ +PRIVATE INLINE int magic_range_is_heap(void *addr) +{ + void* heap_range[2]; + MAGIC_RANGE_SET_MIN(heap_range, magic_heap_start); + MAGIC_RANGE_SET_MAX(heap_range, (char *)magic_heap_end + MAGIC_HEAP_GAP); + MAGIC_RANGE_DEBUG_ADDR(addr, heap_range); + return MAGIC_ADDR_IS_IN_RANGE(addr, heap_range) ? MAGIC_STATE_HEAP : 0; +} + +/*===========================================================================* + * magic_range_is_stack * + *===========================================================================*/ +PUBLIC int magic_range_is_stack(void *addr) +{ + /* + * NB!: This function requires the calling thread to already + * hold the DSENTRY lock. + */ + struct _magic_sentry *sentry; + int ret; + void *stack_range[2]; + + MAGIC_RANGE_INIT(stack_range); + assert(_magic_first_stack_dsentry && _magic_last_stack_dsentry); + sentry = MAGIC_DSENTRY_TO_SENTRY(_magic_first_stack_dsentry); + MAGIC_RANGE_SET_MIN(stack_range, + (char *) MAGIC_DSENTRY_TO_SENTRY(_magic_last_stack_dsentry)->address - + MAGIC_STACK_GAP); + MAGIC_RANGE_SET_MAX(stack_range, + ((char *) sentry->address) + sentry->type->size - 1); +#if MAGIC_RANGE_ROUND_STACK + MAGIC_RANGE_PAGE_ROUND(stack_range); +#endif + MAGIC_RANGE_DEBUG_ADDR(addr, stack_range); + ret = MAGIC_ADDR_IS_IN_RANGE(addr, stack_range) ? MAGIC_STATE_STACK : 0; + + return ret; +} + +/*===========================================================================* + * magic_range_is_dsentry * + *===========================================================================*/ +PUBLIC int magic_range_is_dsentry(void *addr) +{ + /* + * NB!: This function requires the calling thread to already + * hold the DSENTRY lock. + */ + int ret = 0; + void *start_address, *end_address; + struct _magic_dsentry *prev_dsentry, *dsentry; + struct _magic_sentry *sentry; + int region; + + if(magic_update_dsentry_ranges) { + MAGIC_RANGE_INIT(magic_heap_range); + MAGIC_RANGE_INIT(magic_map_range); + MAGIC_RANGE_INIT(magic_shm_range); + MAGIC_RANGE_INIT(magic_stack_range); + MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry, + start_address = sentry->address; + end_address = (void *) (((char *)sentry->address) + + sentry->type->size - 1); + region = MAGIC_STATE_REGION(sentry); + if(region & MAGIC_STATE_HEAP) { + MAGIC_RANGE_UPDATE(magic_heap_range, start_address, end_address); + } + else if(region & MAGIC_STATE_MAP) { + MAGIC_RANGE_UPDATE(magic_map_range, start_address, end_address); + } + else if(region & MAGIC_STATE_SHM) { + MAGIC_RANGE_UPDATE(magic_shm_range, start_address, end_address); + } + else if(region & MAGIC_STATE_STACK) { + MAGIC_RANGE_UPDATE(magic_stack_range, start_address, end_address); + } + ); + magic_update_dsentry_ranges = 0; + } + MAGIC_RANGE_DEBUG_ADDR(addr, magic_heap_range); + if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_heap_range)) { + ret |= MAGIC_STATE_HEAP; + } + MAGIC_RANGE_DEBUG_ADDR(addr, magic_map_range); + if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_map_range)) { + ret |= MAGIC_STATE_MAP; + } + MAGIC_RANGE_DEBUG_ADDR(addr, magic_shm_range); + if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_shm_range)) { + ret |= MAGIC_STATE_SHM; + } + MAGIC_RANGE_DEBUG_ADDR(addr, magic_stack_range); + if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_stack_range)) { + ret |= MAGIC_STATE_STACK; + } + + return ret; +} + +/*===========================================================================* + * magic_range_is_dfunction * + *===========================================================================*/ +PUBLIC int magic_range_is_dfunction(void *addr) +{ + /* + * NB!: This function requires the calling thread to already + * hold the DFUNCTION lock. + */ + int ret = 0; + void *start_address; + struct _magic_dfunction* dfunction; + struct _magic_function* function; + int region; + + if(magic_update_dfunction_ranges) { + MAGIC_RANGE_INIT(magic_dfunction_range); + MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function, + start_address = function->address; + region = MAGIC_STATE_REGION(function); + assert(region & MAGIC_STATE_TEXT); + MAGIC_RANGE_UPDATE(magic_dfunction_range, start_address, start_address); + ); + magic_update_dfunction_ranges = 0; + } + MAGIC_RANGE_DEBUG_ADDR(addr, magic_dfunction_range); + if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_dfunction_range)) { + ret |= MAGIC_STATE_TEXT; + } + + return ret; +} + +/*===========================================================================* + * magic_ranges_init * + *===========================================================================*/ +PUBLIC void magic_ranges_init(void) +{ + int i,j; + void *start_address, *end_address; + void* linker_vars[] = { MAGIC_LINKER_VAR_NAMES }; + + /* Init sentry and data range. */ + MAGIC_RANGE_INIT(magic_data_range); + MAGIC_RANGE_INIT(magic_sentry_range); + for (i = 0 ; i < _magic_sentries_num ; i++) { + start_address = _magic_sentries[i].address; + end_address = (void *) (((char *)_magic_sentries[i].address)+_magic_sentries[i].type->size-1); + MAGIC_RANGE_UPDATE(magic_sentry_range, start_address, end_address); + j = 0; + while (linker_vars[j] && strcmp(linker_vars[j], _magic_sentries[i].name)) j++; + if (linker_vars[j] || MAGIC_STATE_FLAG(&_magic_sentries[i], MAGIC_STATE_THREAD_LOCAL) + || MAGIC_STATE_FLAG(&_magic_sentries[i], MAGIC_STATE_EXTERNAL)) { + continue; + } + MAGIC_RANGE_UPDATE(magic_data_range, start_address, end_address); + } +#if MAGIC_RANGE_ROUND_DATA + MAGIC_RANGE_PAGE_ROUND(magic_data_range); +#endif + + /* Init function range. */ + MAGIC_RANGE_INIT(magic_function_range); + for (i = 0 ; i < _magic_functions_num ; i++) { + start_address = _magic_functions[i].address; + MAGIC_RANGE_UPDATE(magic_function_range, start_address, start_address); + } + + /* Init text range. */ +#ifdef __MINIX + MAGIC_RANGE_SET(magic_text_range, MAGIC_TEXT_START, + MAGIC_TEXT_END ? MAGIC_TEXT_END : ((char *)magic_function_range[1])); +#else + MAGIC_RANGE_SET(magic_text_range, MAGIC_TEXT_START, + MAGIC_TEXT_END ? MAGIC_TEXT_END : ((char *)magic_data_range[0] - 1)); +#endif +#if MAGIC_RANGE_ROUND_TEXT + MAGIC_RANGE_PAGE_ROUND(magic_text_range); +#endif + + /* Init heap start. */ + magic_heap_start = MAGIC_HEAP_START ? MAGIC_HEAP_START : ((char *)magic_data_range[1] + 1); + magic_heap_end = ((char *)sbrk(0)) - 1; + + /* Defaults for other ranges. */ + MAGIC_RANGE_INIT(magic_heap_range); + MAGIC_RANGE_INIT(magic_map_range); + MAGIC_RANGE_INIT(magic_shm_range); + MAGIC_RANGE_INIT(magic_stack_range); + MAGIC_RANGE_INIT(magic_dfunction_range); +} + +/*===========================================================================* + * magic_range_lookup_by_addr * + *===========================================================================*/ +PUBLIC int magic_range_lookup_by_addr(void *addr, void **container) +{ + /* + * NB!: This function requires the calling thread to already + * hold the DSENTRY, DFUNCTION and DSODESC locks. + */ + int ret; + /* Constant ranges first. */ + if (magic_range_is_data(addr)) { + return MAGIC_STATE_DATA; + } + if (magic_range_is_text(addr)) { + return MAGIC_STATE_TEXT; + } + + /* Non-dsentry ranges next. */ + if (magic_range_is_heap(addr)) { + return MAGIC_STATE_HEAP; + } + if (magic_range_is_stack(addr)) { + return MAGIC_STATE_STACK; + } + + /* Shared library ranges. */ +#if 0 + /* XXX: This kind of range isn't very accurate. */ + if (magic_range_is_dfunction(addr)) { + return MAGIC_STATE_LIB | MAGIC_STATE_TEXT; + } +#endif + + if ((ret = magic_range_is_shlib(addr, container))) { + return ret; + } + + /* Dsentry ranges last. */ + return magic_range_is_dsentry(addr); +} + + diff --git a/minix/llvm/static/magic/magic_selement.c b/minix/llvm/static/magic/magic_selement.c new file mode 100644 index 000000000..8588715e1 --- /dev/null +++ b/minix/llvm/static/magic/magic_selement.c @@ -0,0 +1,935 @@ +#include + +/*===========================================================================* + * 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_idparent_namenamesite_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;inum_child_types;i++) { + if(!strcmp(parent_type->member_names[i], name)) { + child_num = i; + break; + } + } + if(i == parent_type->num_child_types) { + return NULL; + } + break; + + case MAGIC_TYPE_POINTER: + i = magic_selement_recurse_ptr(parent_selement, selement, MAGIC_SELEMENT_MAX_PTR_RECURSIONS); + if(i <= 0 || i >= MAGIC_SELEMENT_MAX_PTR_RECURSIONS) { + return NULL; + } + new_parent_selement = *selement; + return magic_selement_from_relative_name(&new_parent_selement, selement, name); + break; + + default: + return NULL; + break; + } + + if(child_num != -1) { + selement->sentry = parent_selement->sentry; + selement->parent_type = parent_type; + selement->parent_address = parent_selement->address; + selement->child_num = child_num; + selement->num = parent_selement->num+1; + magic_selement_fill_from_parent_info(selement, walk_flags); + } + + return selement; +} + diff --git a/minix/llvm/static/magic/magic_sentry.c b/minix/llvm/static/magic/magic_sentry.c new file mode 100644 index 000000000..abf24ffd8 --- /dev/null +++ b/minix/llvm/static/magic/magic_sentry.c @@ -0,0 +1,919 @@ +#include +#include + +/*===========================================================================* + * 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: <%08x, %08x>\n", (unsigned int) node->key, + (unsigned int) node->value); + return 0; +} + +/*===========================================================================* + * magic_sentry_rl_print_index * + *===========================================================================*/ +PUBLIC void magic_sentry_rl_print_index(void) +{ + size_t num_nodes = 0; + assert(magic_sentry_rl_index); + + splay_tree_foreach((splay_tree) magic_sentry_rl_index, + magic_sentry_rl_count_index_cb, &num_nodes); + _magic_printf("magic_sentry_rl_print_index: Found %d nodes:\n", num_nodes); + splay_tree_foreach((splay_tree) magic_sentry_rl_index, + magic_sentry_rl_print_index_cb, NULL); +} + +/*===========================================================================* + * magic_sentry_rl_lookup * + *===========================================================================*/ +PUBLIC struct _magic_sentry *magic_sentry_rl_lookup(void *start_addr) +{ + splay_tree_node node; + struct _magic_sentry *sentry = NULL; + + node = splay_tree_lookup((splay_tree) magic_sentry_rl_index, + (splay_tree_key) start_addr); + if (node) { + sentry = (struct _magic_sentry*) node->value; + } + + return sentry; +} + +/*===========================================================================* + * magic_sentry_rl_insert * + *===========================================================================*/ +PUBLIC struct _magic_sentry *magic_sentry_rl_insert(void *start_addr, + struct _magic_sentry *sentry) +{ + if (!splay_tree_lookup((splay_tree) magic_sentry_rl_index, + (splay_tree_key) start_addr)) { + splay_tree_insert((splay_tree) magic_sentry_rl_index, + (splay_tree_key) start_addr, + (splay_tree_value) sentry); + } + else { + sentry = NULL; + } + + return sentry; +} + +/*===========================================================================* + * magic_sentry_rl_pred_lookup * + *===========================================================================*/ +PUBLIC struct _magic_sentry *magic_sentry_rl_pred_lookup(void *addr) +{ + splay_tree_node node; + struct _magic_sentry *sentry = NULL; + + node = splay_tree_predecessor((splay_tree) magic_sentry_rl_index, + (splay_tree_key) addr); + if (node) { + sentry = (struct _magic_sentry*) node->value; + } + + return sentry; +} + +/*===========================================================================* + * magic_sentry_lookup_by_range_index * + *===========================================================================*/ +PUBLIC struct _magic_sentry *magic_sentry_lookup_by_range_index( + void *addr, struct _magic_dsentry *dsentry_buff) +{ + /* + * Warning: this implementation is thread unsafe! + */ + void *start_address, *end_address; + struct _magic_sentry *sentry = + magic_sentry_rl_pred_lookup((char *)addr + 1); + + if (sentry) { + start_address = sentry->address; + end_address = (void *) (((char *)start_address) + + sentry->type->size - 1); + if (!MAGIC_ADDR_IS_WITHIN(addr, start_address, end_address)) { + sentry = NULL; + } else { + if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_DYNAMIC) && + dsentry_buff != NULL) { + magic_copy_dsentry(MAGIC_DSENTRY_FROM_SENTRY(sentry), + dsentry_buff); + } + } + } + + return sentry; +} + +/*===========================================================================* + * magic_sentry_hash_insert * + *===========================================================================*/ +PRIVATE void magic_sentry_hash_insert(struct _magic_sentry_hash **head, + struct _magic_sentry_hash *elem) +{ + if (head != NULL) { + struct _magic_sentry_hash *tmp; + HASH_FIND_STR(*head, elem->key, tmp); + if (tmp) { + LL_APPEND(tmp->sentry_list, elem->sentry_list); + return; + } + } +/* + * **** START UTHASH SPECIFIC DEFINITIONS **** + */ +#undef uthash_malloc +#undef uthash_free +#define uthash_malloc(size) magic_sentry_hash_alloc(size) +#define uthash_free(addr, size) magic_sentry_hash_dealloc(addr, size) +/* + * Since we have a limited buffer, we need to stop bucket expansion when + * reaching a certain limit. + */ +#undef uthash_expand_fyi +#define uthash_expand_fyi(tbl) \ + do { \ + if (tbl->num_buckets == MAGIC_SENTRY_NAME_EST_MAX_BUCKETS) { \ + _magic_printf("Warning! Sentry name hash maximum bucket number " \ + "reached! Consider increasing " \ + "MAGIC_SENTRY_NAME_EST_MAX_BUCKETS, unless you are comfortable"\ + " with the current performance.\n"); \ + tbl->noexpand = 1; \ + } \ + } while(0); +/* + * **** FINISH UTHASH SPECIFIC DEFINITIONS **** + */ + HASH_ADD_STR(*head, key, elem); +/* + * **** START UTHASH DEFINITION REMOVAL **** + */ +#undef uthash_malloc +#undef uthash_free +#undef uthash_expand_fyi +/* + * **** FINISH UTHASH DEFINITION REMOVAL **** + */ +} + +/*===========================================================================* + * magic_sentry_hash_build * + *===========================================================================*/ +PUBLIC void magic_sentry_hash_build(void *buff, size_t buff_size) +{ + /* + * XXX: + * Warning: this implementation is thread unsafe and also makes + * magic_sentry_lookup_by_name thread unsafe! + */ + int i; + struct _magic_dsentry *prev_dsentry, *dsentry; + struct _magic_sentry *sentry; + struct _magic_sentry_hash *sentry_hash, *head; + struct _magic_sentry_list *sentry_list; + + assert(buff && buff_size > 0); + magic_sentry_hash_buff = buff; + magic_sentry_hash_buff_offset = 0; + magic_sentry_hash_buff_size = buff_size; + + head = NULL; + + /* Add all the sentries to the hash. */ +#if MAGIC_LOOKUP_SENTRY + for(i = 0 ; i < _magic_sentries_num ; i++) { + sentry_hash = (struct _magic_sentry_hash *) + magic_sentry_hash_alloc(sizeof(struct _magic_sentry_hash)); + sentry_list = (struct _magic_sentry_list *) + magic_sentry_hash_alloc(sizeof(struct _magic_sentry_list)); + sentry = &_magic_sentries[i]; + MAGIC_SENTRY_TO_HASH_EL(sentry, sentry_hash, sentry_list); + magic_sentry_hash_insert(&head, sentry_hash); + } +#endif + + /* Add all the dsentries to the hash. */ +#if MAGIC_LOOKUP_DSENTRY + MAGIC_DSENTRY_LOCK(); + MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry, + sentry_hash = (struct _magic_sentry_hash *) + magic_sentry_hash_alloc(sizeof(struct _magic_sentry_hash)); + sentry_list = (struct _magic_sentry_list *) + magic_sentry_hash_alloc(sizeof(struct _magic_sentry_list)); + MAGIC_DSENTRY_TO_HASH_EL(dsentry, sentry, sentry_hash, sentry_list); + magic_sentry_hash_insert(&head, sentry_hash); + ); + MAGIC_DSENTRY_UNLOCK(); +#endif + magic_sentry_hash_head = (void *)head; + assert(magic_sentry_hash_head || (!_magic_sentries_num && _magic_first_dsentry == NULL)); +} + +/*===========================================================================* + * magic_sentry_hash_destroy * + *===========================================================================*/ +PUBLIC void magic_sentry_hash_destroy(void) +{ + magic_sentry_hash_buff = NULL; + magic_sentry_hash_buff_offset = 0; + magic_sentry_hash_buff_size = 0; + magic_sentry_hash_head = NULL; +} + +/*===========================================================================* + * magic_sentry_hash_estimate_buff_size * + *===========================================================================*/ +PUBLIC size_t magic_sentry_hash_estimate_buff_size(int sentries_num) +{ + if (sentries_num == 0) { + MAGIC_DSENTRY_ALIVE_NUM(_magic_first_dsentry, &sentries_num); + sentries_num += _magic_sentries_num; + } + + return (sentries_num * (sizeof(struct _magic_sentry_hash) + + sizeof(struct _magic_sentry_list))) + MAGIC_SENTRY_NAME_HASH_OVERHEAD; +} + +/*===========================================================================* + * magic_sentry_hash_alloc * + *===========================================================================*/ +PUBLIC void *magic_sentry_hash_alloc(size_t size) +{ + void *addr; + + assert(magic_sentry_hash_buff); + assert(magic_sentry_hash_buff_offset + size <= magic_sentry_hash_buff_size); + + addr = (char *) magic_sentry_hash_buff + magic_sentry_hash_buff_offset; + magic_sentry_hash_buff_offset += size; + + return addr; +} + +/*===========================================================================* + * magic_sentry_hash_dealloc * + *===========================================================================*/ +PUBLIC void magic_sentry_hash_dealloc(UNUSED(void *object), UNUSED(size_t sz)) +{ + return; +} + +/*===========================================================================* + * magic_sentry_lookup_by_name_hash * + *===========================================================================*/ +PUBLIC struct _magic_sentry *magic_sentry_lookup_by_name_hash( + char *parent_name, char *name, _magic_id_t site_id, + struct _magic_dsentry *dsentry_buff) +{ + /* + * Warning: this implementation is thread unsafe! + */ + char key[MAGIC_SENTRY_NAME_MAX_KEY_LEN]; + struct _magic_sentry_hash *res, *head; + key[0] = 0; + sprintf(key, "%s%s%s%s" MAGIC_ID_FORMAT, parent_name, + MAGIC_DSENTRY_ABS_NAME_SEP, name, MAGIC_DSENTRY_ABS_NAME_SEP, site_id); + head = (struct _magic_sentry_hash *) magic_sentry_hash_head; + + HASH_FIND_STR(head, key, res); + if (res == NULL) + return NULL; + + return res->sentry_list->sentry; +} + +/*===========================================================================* + * magic_sentry_list_lookup_by_name_hash * + *===========================================================================*/ +PUBLIC struct _magic_sentry_list *magic_sentry_list_lookup_by_name_hash( + char *parent_name, char *name, _magic_id_t site_id, + struct _magic_dsentry *dsentry_buff) +{ + /* + * Warning: this implementation is thread unsafe! + */ + char key[MAGIC_SENTRY_NAME_MAX_KEY_LEN]; + struct _magic_sentry_hash *res, *head; + key[0] = 0; + sprintf(key, "%s%s%s%s" MAGIC_ID_FORMAT, parent_name, + MAGIC_DSENTRY_ABS_NAME_SEP, name, MAGIC_DSENTRY_ABS_NAME_SEP, site_id); + head = (struct _magic_sentry_hash *) magic_sentry_hash_head; + + HASH_FIND_STR(head, key, res); + if (res == NULL) + return NULL; + + return res->sentry_list; +} + diff --git a/minix/llvm/static/magic/magic_splay_tree.c b/minix/llvm/static/magic/magic_splay_tree.c new file mode 100644 index 000000000..e8247edbc --- /dev/null +++ b/minix/llvm/static/magic/magic_splay_tree.c @@ -0,0 +1,523 @@ +/* A splay-tree datatype. + Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street - Fifth Floor, +Boston, MA 02110-1301, USA. */ + +/* For an easily readable description of splay-trees, see: + + Lewis, Harry R. and Denenberg, Larry. Data Structures and Their + Algorithms. Harper-Collins, Inc. 1991. */ + +#include +#include + +#include "magic_splay_tree.h" + +#ifndef xmalloc +#define xmalloc malloc +#endif + +static void splay_tree_delete_helper (splay_tree, splay_tree_node); +static inline void rotate_left (splay_tree_node *, + splay_tree_node, splay_tree_node); +static inline void rotate_right (splay_tree_node *, + splay_tree_node, splay_tree_node); +static void splay_tree_splay (splay_tree, splay_tree_key); +static int splay_tree_foreach_helper (splay_tree, splay_tree_node, + splay_tree_foreach_fn, void*); + +/* Deallocate NODE (a member of SP), and all its sub-trees. */ + +static void +splay_tree_delete_helper (splay_tree sp, splay_tree_node node) +{ + splay_tree_node pending = 0; + splay_tree_node active = 0; + + if (!node) + return; + +#define KDEL(x) if (sp->delete_key) (*sp->delete_key)(x); +#define VDEL(x) if (sp->delete_value) (*sp->delete_value)(x); + + KDEL (node->key); + VDEL (node->value); + + /* We use the "key" field to hold the "next" pointer. */ + node->key = (splay_tree_key)pending; + pending = (splay_tree_node)node; + + /* Now, keep processing the pending list until there aren't any + more. This is a little more complicated than just recursing, but + it doesn't toast the stack for large trees. */ + + while (pending) + { + active = pending; + pending = 0; + while (active) + { + splay_tree_node temp; + + /* active points to a node which has its key and value + deallocated, we just need to process left and right. */ + + if (active->left) + { + KDEL (active->left->key); + VDEL (active->left->value); + active->left->key = (splay_tree_key)pending; + pending = (splay_tree_node)(active->left); + } + if (active->right) + { + KDEL (active->right->key); + VDEL (active->right->value); + active->right->key = (splay_tree_key)pending; + pending = (splay_tree_node)(active->right); + } + + temp = active; + active = (splay_tree_node)(temp->key); + (*sp->deallocate) ((char*) temp, sp->allocate_data); + } + } +#undef KDEL +#undef VDEL +} + +/* Rotate the edge joining the left child N with its parent P. PP is the + grandparents pointer to P. */ + +static inline void +rotate_left (splay_tree_node *pp, splay_tree_node p, splay_tree_node n) +{ + splay_tree_node tmp; + tmp = n->right; + n->right = p; + p->left = tmp; + *pp = n; +} + +/* Rotate the edge joining the right child N with its parent P. PP is the + grandparents pointer to P. */ + +static inline void +rotate_right (splay_tree_node *pp, splay_tree_node p, splay_tree_node n) +{ + splay_tree_node tmp; + tmp = n->left; + n->left = p; + p->right = tmp; + *pp = n; +} + +/* Bottom up splay of key. */ + +static void +splay_tree_splay (splay_tree sp, splay_tree_key key) +{ + if (sp->root == 0) + return; + + do { + int cmp1, cmp2; + splay_tree_node n, c; + + n = sp->root; + cmp1 = (*sp->comp) (key, n->key); + + /* Found. */ + if (cmp1 == 0) + return; + + /* Left or right? If no child, then we're done. */ + if (cmp1 < 0) + c = n->left; + else + c = n->right; + if (!c) + return; + + /* Next one left or right? If found or no child, we're done + after one rotation. */ + cmp2 = (*sp->comp) (key, c->key); + if (cmp2 == 0 + || (cmp2 < 0 && !c->left) + || (cmp2 > 0 && !c->right)) + { + if (cmp1 < 0) + rotate_left (&sp->root, n, c); + else + rotate_right (&sp->root, n, c); + return; + } + + /* Now we have the four cases of double-rotation. */ + if (cmp1 < 0 && cmp2 < 0) + { + rotate_left (&n->left, c, c->left); + rotate_left (&sp->root, n, n->left); + } + else if (cmp1 > 0 && cmp2 > 0) + { + rotate_right (&n->right, c, c->right); + rotate_right (&sp->root, n, n->right); + } + else if (cmp1 < 0 && cmp2 > 0) + { + rotate_right (&n->left, c, c->right); + rotate_left (&sp->root, n, n->left); + } + else if (cmp1 > 0 && cmp2 < 0) + { + rotate_left (&n->right, c, c->left); + rotate_right (&sp->root, n, n->right); + } + } while (1); +} + +/* Call FN, passing it the DATA, for every node below NODE, all of + which are from SP, following an in-order traversal. If FN every + returns a non-zero value, the iteration ceases immediately, and the + value is returned. Otherwise, this function returns 0. */ + +static int +splay_tree_foreach_helper (splay_tree sp, splay_tree_node node, + splay_tree_foreach_fn fn, void *data) +{ + int val; + + if (!node) + return 0; + + val = splay_tree_foreach_helper (sp, node->left, fn, data); + if (val) + return val; + + val = (*fn)(node, data); + if (val) + return val; + + return splay_tree_foreach_helper (sp, node->right, fn, data); +} + + +/* An allocator and deallocator based on xmalloc. */ +static void * +splay_tree_xmalloc_allocate (int size, void *data ATTRIBUTE_UNUSED) +{ + return (void *) xmalloc (size); +} + +static void +splay_tree_xmalloc_deallocate (void *object, void *data ATTRIBUTE_UNUSED) +{ + free (object); +} + + +/* Allocate a new splay tree, using COMPARE_FN to compare nodes, + DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate + values. Use xmalloc to allocate the splay tree structure, and any + nodes added. */ + +splay_tree +splay_tree_new (splay_tree_compare_fn compare_fn, + splay_tree_delete_key_fn delete_key_fn, + splay_tree_delete_value_fn delete_value_fn) +{ + return (splay_tree_new_with_allocator + (compare_fn, delete_key_fn, delete_value_fn, + splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate, 0)); +} + + +/* Allocate a new splay tree, using COMPARE_FN to compare nodes, + DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate + values. */ + +splay_tree +splay_tree_new_with_allocator (splay_tree_compare_fn compare_fn, + splay_tree_delete_key_fn delete_key_fn, + splay_tree_delete_value_fn delete_value_fn, + splay_tree_allocate_fn allocate_fn, + splay_tree_deallocate_fn deallocate_fn, + void *allocate_data) +{ + splay_tree sp = (splay_tree) (*allocate_fn) (sizeof (struct splay_tree_s), + allocate_data); + sp->root = 0; + sp->comp = compare_fn; + sp->delete_key = delete_key_fn; + sp->delete_value = delete_value_fn; + sp->allocate = allocate_fn; + sp->deallocate = deallocate_fn; + sp->allocate_data = allocate_data; + + return sp; +} + +/* Deallocate SP. */ + +void +splay_tree_delete (splay_tree sp) +{ + splay_tree_delete_helper (sp, sp->root); + (*sp->deallocate) ((char*) sp, sp->allocate_data); +} + +/* Insert a new node (associating KEY with DATA) into SP. If a + previous node with the indicated KEY exists, its data is replaced + with the new value. Returns the new node. */ + +splay_tree_node +splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value) +{ + int comparison = 0; + + splay_tree_splay (sp, key); + + if (sp->root) + comparison = (*sp->comp)(sp->root->key, key); + + if (sp->root && comparison == 0) + { + /* If the root of the tree already has the indicated KEY, just + replace the value with VALUE. */ + if (sp->delete_value) + (*sp->delete_value)(sp->root->value); + sp->root->value = value; + } + else + { + /* Create a new node, and insert it at the root. */ + splay_tree_node node; + + node = ((splay_tree_node) + (*sp->allocate) (sizeof (struct splay_tree_node_s), + sp->allocate_data)); + node->key = key; + node->value = value; + + if (!sp->root) + node->left = node->right = 0; + else if (comparison < 0) + { + node->left = sp->root; + node->right = node->left->right; + node->left->right = 0; + } + else + { + node->right = sp->root; + node->left = node->right->left; + node->right->left = 0; + } + + sp->root = node; + } + + return sp->root; +} + +/* Remove KEY from SP. It is not an error if it did not exist. */ + +void +splay_tree_remove (splay_tree sp, splay_tree_key key) +{ + splay_tree_splay (sp, key); + + if (sp->root && (*sp->comp) (sp->root->key, key) == 0) + { + splay_tree_node left, right; + + left = sp->root->left; + right = sp->root->right; + + /* Delete the root node itself. */ + if (sp->delete_value) + (*sp->delete_value) (sp->root->value); + (*sp->deallocate) (sp->root, sp->allocate_data); + + /* One of the children is now the root. Doesn't matter much + which, so long as we preserve the properties of the tree. */ + if (left) + { + sp->root = left; + + /* If there was a right child as well, hang it off the + right-most leaf of the left child. */ + if (right) + { + while (left->right) + left = left->right; + left->right = right; + } + } + else + sp->root = right; + } +} + +/* Lookup KEY in SP, returning VALUE if present, and NULL + otherwise. */ + +splay_tree_node +splay_tree_lookup (splay_tree sp, splay_tree_key key) +{ + splay_tree_splay (sp, key); + + if (sp->root && (*sp->comp)(sp->root->key, key) == 0) + return sp->root; + else + return 0; +} + +/* Return the node in SP with the greatest key. */ + +splay_tree_node +splay_tree_max (splay_tree sp) +{ + splay_tree_node n = sp->root; + + if (!n) + return NULL; + + while (n->right) + n = n->right; + + return n; +} + +/* Return the node in SP with the smallest key. */ + +splay_tree_node +splay_tree_min (splay_tree sp) +{ + splay_tree_node n = sp->root; + + if (!n) + return NULL; + + while (n->left) + n = n->left; + + return n; +} + +/* Return the immediate predecessor KEY, or NULL if there is no + predecessor. KEY need not be present in the tree. */ + +splay_tree_node +splay_tree_predecessor (splay_tree sp, splay_tree_key key) +{ + int comparison; + splay_tree_node node; + + /* If the tree is empty, there is certainly no predecessor. */ + if (!sp->root) + return NULL; + + /* Splay the tree around KEY. That will leave either the KEY + itself, its predecessor, or its successor at the root. */ + splay_tree_splay (sp, key); + comparison = (*sp->comp)(sp->root->key, key); + + /* If the predecessor is at the root, just return it. */ + if (comparison < 0) + return sp->root; + + /* Otherwise, find the rightmost element of the left subtree. */ + node = sp->root->left; + if (node) + while (node->right) + node = node->right; + + return node; +} + +/* Return the immediate successor KEY, or NULL if there is no + successor. KEY need not be present in the tree. */ + +splay_tree_node +splay_tree_successor (splay_tree sp, splay_tree_key key) +{ + int comparison; + splay_tree_node node; + + /* If the tree is empty, there is certainly no successor. */ + if (!sp->root) + return NULL; + + /* Splay the tree around KEY. That will leave either the KEY + itself, its predecessor, or its successor at the root. */ + splay_tree_splay (sp, key); + comparison = (*sp->comp)(sp->root->key, key); + + /* If the successor is at the root, just return it. */ + if (comparison > 0) + return sp->root; + + /* Otherwise, find the leftmost element of the right subtree. */ + node = sp->root->right; + if (node) + while (node->left) + node = node->left; + + return node; +} + +/* Call FN, passing it the DATA, for every node in SP, following an + in-order traversal. If FN every returns a non-zero value, the + iteration ceases immediately, and the value is returned. + Otherwise, this function returns 0. */ + +int +splay_tree_foreach (splay_tree sp, splay_tree_foreach_fn fn, void *data) +{ + return splay_tree_foreach_helper (sp, sp->root, fn, data); +} + +/* Splay-tree comparison function, treating the keys as ints. */ + +int +splay_tree_compare_ints (splay_tree_key k1, splay_tree_key k2) +{ + if ((int) k1 < (int) k2) + return -1; + else if ((int) k1 > (int) k2) + return 1; + else + return 0; +} + +/* Splay-tree comparison function, treating the keys as pointers. */ + +int +splay_tree_compare_pointers (splay_tree_key k1, splay_tree_key k2) +{ + if ((char*) k1 < (char*) k2) + return -1; + else if ((char*) k1 > (char*) k2) + return 1; + else + return 0; +} + diff --git a/minix/llvm/static/magic/magic_st.c b/minix/llvm/static/magic/magic_st.c new file mode 100644 index 000000000..69fcc0dde --- /dev/null +++ b/minix/llvm/static/magic/magic_st.c @@ -0,0 +1,4542 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define printf _magic_printf + +#ifdef __MINIX +EXTERN endpoint_t sef_self_endpoint; +#else +#define DO_SKIP_ENVIRON_HACK 1 +#define TODO_DSENTRY_PARENT_NAME_BUG 1 +#define DO_SKIP_UNPAIRED_PTR_TARGETS 1 +#endif + +#define DO_SKIP_INVARIANTS_VIOLATIONS 1 + +PRIVATE st_alloc_pages *st_alloc_pages_current = NULL; +PRIVATE int st_alloc_buff_available = 0; +PRIVATE char *st_alloc_buff_pt = NULL; +PRIVATE char *st_pre_allocated_page_pt = NULL; +PRIVATE struct _magic_dsentry *st_dsentry_buff = NULL; +PRIVATE void *st_data_buff = NULL; +PRIVATE unsigned st_num_type_transformations = 0; + +/* Magic variables and counterparts. */ +struct _magic_vars_t st_remote_magic_vars, st_cached_magic_vars; +struct _magic_vars_t *st_local_magic_vars_ptr = &_magic_vars_buff; +st_counterparts_t st_counterparts; + +/* Private variables. */ +PRIVATE int st_init_done = FALSE; +PRIVATE int st_policies = ST_POLICIES_DEFAULT; +PRIVATE double st_unpaired_types_ratio = ST_UNPAIRED_TYPES_RATIO_DEFAULT; +PRIVATE double st_unpaired_struct_types_ratio = ST_UNPAIRED_STRUCT_TYPES_RATIO_DEFAULT; + +/* Forward declarations. */ +PRIVATE INLINE int default_transfer_selement_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info); + +/* State transfer callbacks. */ + +PRIVATE struct st_cbs_t st_cbs = { + ST_CB_PAGES_ALLOCATE_DEFAULT, + ST_CB_PAGES_FREE_DEFAULT, + ST_CB_STATE_CLEANUP_DEFAULT, + ST_CB_STATE_CHECKING_DEFAULT, + ST_CB_SELEMENT_MAP_DEFAULT, + ST_CB_SELEMENT_TRANSFER_EMPTY +}; + +/* OS dependent callbacks. */ +PRIVATE struct st_cbs_os_t st_cbs_os = { + ST_CB_OS_PANIC_EMPTY, + ST_CB_OS_OLD_STATE_TABLE_LOOKUP_EMPTY, + ST_CB_OS_COPY_STATE_REGION_EMPTY, + ST_CB_OS_ALLOC_CONTIG_EMPTY, + ST_CB_OS_FREE_CONTIG_EMPTY, + ST_CB_OS_DEBUG_HEADER_EMPTY +}; + +/* State transfer prototypes for st_receive(). */ +PUBLIC void do_st_before_receive(void); + +/* Callback setters */ + +PUBLIC void st_setcb_pages_allocate (st_cb_pages_allocate_t cb) +{ + assert(cb != NULL); + st_cbs.st_cb_pages_allocate = cb; +} + +PUBLIC void st_setcb_pages_free (st_cb_pages_free_t cb) +{ + assert(cb != NULL); + st_cbs.st_cb_pages_free = cb; +} + +PUBLIC void st_setcb_state_cleanup (st_cb_state_cleanup_t cb) +{ + assert(cb != NULL); + st_cbs.st_cb_state_cleanup = cb; + magic_setcb_sentries_analyze_pre(cb); +} + +PUBLIC void st_setcb_state_checking (st_cb_state_checking_t cb) +{ + assert(cb != NULL); + st_cbs.st_cb_state_checking = cb; +} + +PUBLIC void st_setcb_selement_map(st_cb_selement_map_t cb) +{ + assert(cb != NULL); + st_cbs.st_cb_selement_map = cb; +} + +PUBLIC void st_setcb_selement_transfer(st_cb_selement_transfer_t cb, int flags) +{ + int i, j; + for (i = 0 ; i < NUM_CB_ARRAYS ; i++) { + if (i & flags) { + int is_registered = FALSE; + for (j = 0; j < MAX_NUM_CBS ; j++) { + if (st_cbs.st_cb_selement_transfer[i][j] == NULL) { + st_cbs.st_cb_selement_transfer[i][j] = cb; + is_registered = TRUE; + break; + } + } + assert(is_registered && "Number of registered callbacks exceeds MAX_NUM_CBS"); + } + } +} + +/* OS Callback setters. */ + +PUBLIC void st_setcb_os_panic(st_cb_os_panic_t cb) +{ + assert(cb != NULL && "No callback defined for panic()."); + st_cbs_os.panic = cb; +} + +PUBLIC void st_setcb_os_old_state_table_lookup(st_cb_os_old_state_table_lookup_t cb) +{ + assert(cb != NULL && "No callback defined for old_state_table_lookup()."); + st_cbs_os.old_state_table_lookup = cb; +} + +PUBLIC void st_setcb_os_copy_state_region(st_cb_os_copy_state_region_t cb) +{ + assert(cb != NULL && "No callback defined for copy_state_region()."); + st_cbs_os.copy_state_region = cb; +} + +PUBLIC void st_setcb_os_alloc_contig(st_cb_os_alloc_contig_t cb) +{ + assert(cb != NULL && "No callback defined for alloc_contig()."); + st_cbs_os.alloc_contig = cb; +} + +PUBLIC void st_setcb_os_free_contig(st_cb_os_free_contig_t cb) +{ + assert(cb != NULL && "No callback defined for free_contig()."); + st_cbs_os.free_contig = cb; +} + +PUBLIC void st_setcb_os_debug_header(st_cb_os_debug_header_t cb) +{ + assert(cb != NULL && "No callback defined for debug_header()."); + st_cbs_os.debug_header = cb; +} + + +PUBLIC void st_setcb_os_all(struct st_cbs_os_t *cbs) +{ + st_setcb_os_panic(cbs->panic); + st_setcb_os_old_state_table_lookup(cbs->old_state_table_lookup); + st_setcb_os_copy_state_region(cbs->copy_state_region); + st_setcb_os_alloc_contig(cbs->alloc_contig); + st_setcb_os_free_contig(cbs->free_contig); + st_setcb_os_debug_header(cbs->debug_header); +} + +/* Status variables to be transfered at state transfer time. */ +PUBLIC int __st_before_receive_enabled = 0; +PRIVATE int __st_before_receive_sc_max_cycles; +PRIVATE int __st_before_receive_sc_max_violations; + +/* Typedef registration and lookup */ + +int st_strcmp_wildcard(char *with_wildcard, char *without_wildcard) +{ + /* Note: this implementation only supports basic regexes with a '*' + * at the beginning or the end of the string. + */ + char *star = strchr(with_wildcard, '*'); + if (star) { + if (star == with_wildcard) { + size_t len = strlen(with_wildcard+1); + size_t len_without_wildcard = strlen(without_wildcard); + char *match_without_wildcard = without_wildcard+ + len_without_wildcard-len; + if (match_without_wildcard < without_wildcard) { + return -1; + } + return strncmp(with_wildcard+1, match_without_wildcard, len); + } + return strncmp(with_wildcard, without_wildcard, star - with_wildcard); + } + return strcmp(with_wildcard, without_wildcard); +} + +char *st_typename_noxfers[] = { ST_TYPENAME_NO_TRANSFER_NAMES, NULL }; +char *st_typename_ixfers[] = { ST_TYPENAME_IDENTITY_TRANSFER_NAMES, NULL }; +char *st_typename_cixfers[] = { ST_TYPENAME_CIDENTITY_TRANSFER_NAMES, NULL }; +char *st_typename_pxfers[] = { ST_TYPENAME_PTR_TRANSFER_NAMES, NULL }; +char *st_typename_sxfers[] = { ST_TYPENAME_STRUCT_TRANSFER_NAMES, NULL }; +char *st_sentryname_ixfers[] = { ST_SENTRYNAME_IDENTITY_TRANSFER_NAMES, NULL }; +char *st_sentryname_cixfers[] = { ST_SENTRYNAME_CIDENTITY_TRANSFER_NAMES, NULL}; +char *st_sentryname_pxfers[] = { ST_SENTRYNAME_PTR_TRANSFER_NAMES, NULL }; + +/* Exclude stack references in addition to the default sentry names from state transfer. */ +char *st_sentryname_noxfers[] = { + ST_SENTRYNAME_NO_TRANSFER_NAMES, +#define __X(R) #R /* Stringify the symbol names. */ + ST_STACK_REFS_INT_LIST, +#if ST_STACK_REFS_CUSTOM_NUM > 0 + ST_STACK_REFS_CUSTOM_LIST, +#endif +#undef __X + NULL }; + +/* Exclude the data segments of certain libs from state transfer. */ +char *st_dsentry_lib_noxfer[] = { +#ifdef ST_DSENTRYLIB_NO_TRANSFER_NAMES + ST_DSENTRYLIB_NO_TRANSFER_NAMES, +#endif + NULL }; + +char *st_typename_key_registrations[MAX_NUM_TYPENAMES]; + +int is_typename(char *search_key, struct _magic_type *type) +{ + int i; + /* We can't use a cached lookup result */ + if (!st_strcmp_wildcard(search_key, type->name)) { + /* The name matches */ + return TRUE; + } + for (i = 0 ; i < type->num_names ; i++) { + if(!st_strcmp_wildcard(search_key, type->names[i])) { + /* One of the typename names matches */ + return TRUE; + } + } + /* No match is found */ + return FALSE; +} + +PUBLIC void st_register_typename_key(char *key) +{ + int i, is_registered = FALSE; + for(i = 0 ; i < MAX_NUM_TYPENAMES ; i++) { + if (st_typename_key_registrations[i] == NULL) { + st_typename_key_registrations[i] = key; + is_registered = TRUE; + break; + } + } + assert(is_registered && "Error, number of typename registrations > MAX_NUM_TYPENAMES.\n"); +} + +PUBLIC void st_register_typename_keys(char **keys) +{ + int i = 0; + while (keys[i] != NULL) { + st_register_typename_key(keys[i]); + i++; + } +} + +PRIVATE void set_typename_key(struct _magic_type *type) +{ + char **registration = st_typename_key_registrations; + + while (*registration != NULL) { + if (is_typename(*registration, type)) { + type->ext = *registration; + break; + } + registration++; + } +} + +PUBLIC void register_typenames() +{ + + int i; + + /* Register typenames */ + st_register_typename_keys(st_typename_noxfers); + st_register_typename_keys(st_typename_ixfers); + st_register_typename_keys(st_typename_cixfers); + st_register_typename_keys(st_typename_pxfers); + st_register_typename_keys(st_typename_sxfers); + + for(i = 0 ; i < _magic_types_num ; i++) { + set_typename_key(&_magic_types[i]); + } + +} + +PRIVATE INLINE void register_typenames_and_callbacks() +{ + + static int st_is_registered = FALSE; + if(st_is_registered) { + return; + } + + register_typenames(); + + st_setcb_selement_transfer(st_cb_transfer_sentry_default, ST_CB_TYPE_SENTRY); + st_setcb_selement_transfer(st_cb_transfer_typename_default, ST_CB_TYPE_TYPENAME); + + st_is_registered = TRUE; + +} + +PUBLIC int st_type_name_match_any(char **registered_type_name_keys, + char *key) +{ + int i = 0; + while (registered_type_name_keys[i] != NULL) { + if (ST_TYPE_NAME_MATCH(registered_type_name_keys[i], key)) { + return TRUE; + } + i++; + } + return FALSE; +} + +PUBLIC int st_sentry_name_match_any(char **sentry_wildcard_names, + char *name) +{ + int i = 0; + while (sentry_wildcard_names[i] != NULL) { + if (ST_SENTRY_NAME_MATCH(sentry_wildcard_names[i], name)) { + return TRUE; + } + i++; + } + return FALSE; +} + +PUBLIC int st_dsentry_parent_name_match_any(char **wildcard_names, + char *name) +{ + int i = 0; + while (wildcard_names[i] != NULL) { + if (ST_DSENTRY_PARENT_NAME_MATCH(wildcard_names[i], name)) { + return TRUE; + } + i++; + } + return FALSE; +} + +/* Utilities. */ +PUBLIC void st_cb_print(int level, char *msg, _magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + if (ST_CB_PRINT_LEVEL(level)) { + _magic_printf("[%s] %s. Current state element:\n", + ST_CB_LEVEL_TO_STR(level), msg); + MAGIC_SELEMENT_PRINT(selement, MAGIC_EXPAND_TYPE_STR); + _magic_printf("\n"); + MAGIC_SEL_ANALYZED_PRINT(sel_analyzed, MAGIC_EXPAND_TYPE_STR); + _magic_printf("\n"); + MAGIC_SEL_STATS_PRINT(sel_stats); + _magic_printf("\n\n"); + } +} + +PUBLIC void st_cb_selement_type_cast(const struct _magic_type* new_selement_type, const struct _magic_type* new_local_selement_type, _magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + magic_selement_type_cast(selement, ST_SEL_ANALYZE_FLAGS, + new_selement_type, sel_analyzed, sel_stats); + if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) { + cb_info->local_selement->type = new_local_selement_type; + } +} + +/* Stack management. */ + +PUBLIC void st_stack_refs_save_restore(char* stack_buff, int is_save) +{ + struct _magic_dsentry *prev_dsentry, *dsentry; + struct _magic_sentry* sentry; + struct st_stack_refs_buff *buff_ptr; + int i; + +#define __X(P) P + extern int ST_STACK_REFS_INT_LIST; +#undef __X +#define __X(P) ((int *)&(P)) + int* int_ptrs[] = { ST_STACK_REFS_INT_LIST, ST_STACK_REFS_CUSTOM_LIST }; +#undef __X + + assert((ST_STACK_REFS_NUM) == sizeof(int_ptrs)/sizeof(int_ptrs[0])); + assert(sizeof(int) == sizeof(void*)); + buff_ptr = (struct st_stack_refs_buff*) stack_buff; + + /* Save. */ + if (is_save) { + buff_ptr->first_stack_dsentry = _magic_first_stack_dsentry; + buff_ptr->last_stack_dsentry = _magic_last_stack_dsentry; + if (_magic_first_stack_dsentry) { + buff_ptr->first_stack_obdsentry_buff = *MAGIC_OBDSENTRY_FROM_DSENTRY(_magic_first_stack_dsentry); + } + memcpy(buff_ptr->stack_range, magic_stack_range, 2*sizeof(void*)); + for (i = 0 ; i < ST_STACK_REFS_NUM ; i++) { + memcpy(&buff_ptr->stack_int_refs[i], int_ptrs[i], sizeof(int)); + } + return; + } + + /* Restore. */ + if (_magic_first_dsentry == _magic_last_stack_dsentry) { + _magic_first_dsentry = buff_ptr->last_stack_dsentry; + } + else { + MAGIC_DSENTRY_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry, + if (MAGIC_DSENTRY_HAS_NEXT(dsentry) + && MAGIC_DSENTRY_NEXT(dsentry) == _magic_last_stack_dsentry) { + MAGIC_DSENTRY_NEXT(dsentry) = buff_ptr->last_stack_dsentry; + break; + } + ); + } + + _magic_first_stack_dsentry = buff_ptr->first_stack_dsentry; + _magic_last_stack_dsentry = buff_ptr->last_stack_dsentry; + if (_magic_first_stack_dsentry) { + *MAGIC_OBDSENTRY_FROM_DSENTRY(_magic_first_stack_dsentry) = buff_ptr->first_stack_obdsentry_buff; + } + memcpy(magic_stack_range, buff_ptr->stack_range, 2*sizeof(void*)); + for (i = 0 ; i < ST_STACK_REFS_NUM ; i++) { + memcpy(int_ptrs[i], &buff_ptr->stack_int_refs[i], sizeof(int)); + } +} + +/* Metadata management. */ +PUBLIC int st_add_special_mmapped_region(void *address, size_t size, + char* name) +{ + struct _magic_obdsentry* obdsentry; + char addr_name[24]; + + if (!_magic_enabled) return OK; + + if (!name) { + sprintf(addr_name, "%%MMAP_0x%08x", (unsigned int) address); + name = addr_name; + } + obdsentry = magic_create_obdsentry(address, MAGIC_VOID_TYPE, + size, MAGIC_STATE_MAP, name, NULL); + return obdsentry ? OK : EINVAL; +} + +PUBLIC int st_del_special_mmapped_region_by_addr(void *address) +{ + int ret; + + if (!_magic_enabled) return OK; + + ret = magic_destroy_obdsentry_by_addr(address); + if (ret < 0) { + return EINVAL; + } + return OK; +} + +/* Selement transfer callbacks. */ + +PRIVATE INLINE int transfer_walkable_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + /* Do nothing for complex type. process only its members, not the complex type itself */ + return MAGIC_SENTRY_ANALYZE_CONTINUE; +} + +PRIVATE INLINE int transfer_try_raw_copy_sel_cb(_magic_selement_t *selement, struct st_cb_info *cb_info) +{ + /* Only do raw copying if there are no type transformations. */ + if ((selement->type->num_child_types == 0 && selement->type->size == cb_info->local_selement->type->size) || selement->type == cb_info->local_selement->type || ST_TYPE_IS_CACHED_COUNTERPART(selement->type, cb_info->local_selement->type)) { + memcpy(cb_info->local_selement->address, selement->address, cb_info->local_selement->type->size); + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + } + + return MAGIC_SENTRY_ANALYZE_CONTINUE; +} + +PRIVATE INLINE int transfer_identity_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) { + /* First try to do raw copying, assuming there are no type transformations. */ + if (transfer_try_raw_copy_sel_cb(selement, cb_info) == MAGIC_SENTRY_ANALYZE_SKIP_PATH) + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + +#if CHECK_ASR && !FORCE_SOME_UNPAIRED_TYPES + if (cb_info->init_info->flags & ST_LU_ASR) { + st_cbs_os.panic("ASR should never get here!"); + } +#endif + if (selement->type->type_id == MAGIC_TYPE_UNION) { + ST_CB_PRINT(ST_CB_ERR, "uncaught ixfer union with type changes", selement, sel_analyzed, sel_stats, cb_info); + return EFAULT; + } + cb_info->st_cb_flags |= ST_CB_FORCE_IXFER; + return MAGIC_SENTRY_ANALYZE_CONTINUE; + } + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; +} + +PRIVATE INLINE int transfer_cond_identity_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + int r; + int saved_flags = cb_info->st_cb_flags; + cb_info->st_cb_flags &= ~ST_CB_PRINT_ERR; + r = default_transfer_selement_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + cb_info->st_cb_flags = saved_flags; + if (r < 0) { + ST_CB_PRINT(ST_CB_DBG, "conditional ixfer resorting to ixfer", selement, sel_analyzed, sel_stats, cb_info); + return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } + return r; +} + +PRIVATE INLINE int transfer_nonptr_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + if (sel_analyzed->flags & MAGIC_SEL_FOUND_VIOLATIONS) { + ST_CB_PRINT(ST_CB_ERR, "uncaught non-ptr with violations", selement, sel_analyzed, sel_stats, cb_info); + return EFAULT; + } + return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); +} + +PRIVATE int transfer_ptr_sel_with_trg_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + int trg_flags, trg_extf_flags, trg_transferred, trg_paired; + _magic_selement_t cached_trg_selement, local_trg_selement; + void **local_selement_address = cb_info->local_selement->address; + int r; + + r = lookup_trg_info(selement, sel_analyzed, sel_stats, cb_info, &cached_trg_selement, &local_trg_selement); + if (r != OK) { + return r; + } + + trg_flags = sel_analyzed->u.ptr.trg_flags; + trg_extf_flags = MAGIC_STATE_FLAGS_TO_EXTF(trg_flags); + trg_transferred = (trg_extf_flags & (ST_NEEDS_TRANSFER | ST_TRANSFER_DONE)); + trg_paired = (local_trg_selement.type != NULL); + + if (!trg_transferred && trg_paired && (trg_extf_flags & ST_ON_PTRXFER_CASCADE)) { + /* Propagate transfer on the target. */ + if (cached_trg_selement.sentry && !(trg_extf_flags & ST_NEEDS_TRANSFER)) { + ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in cascade transfer for the target", selement, sel_analyzed, sel_stats, cb_info); + st_set_status_by_sentry_id(ST_NEEDS_TRANSFER, ST_OP_ADD, MAGIC_SENTRY_ID(cached_trg_selement.sentry)); + } + /* Force code below to transfer the pointer normally. */ + trg_transferred = TRUE; + } + + if (trg_transferred && trg_paired) { + *local_selement_address = local_trg_selement.address; + } + else if (trg_extf_flags & ST_ON_PTRXFER_SET_NULL) { + ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in forcefully setting ptr to NULL", selement, sel_analyzed, sel_stats, cb_info); + *local_selement_address = NULL; + } + else if(trg_extf_flags & ST_ON_PTRXFER_SET_DEFAULT) { + ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in forcefully setting ptr to default value", selement, sel_analyzed, sel_stats, cb_info); + if (trg_flags & MAGIC_STATE_STRING) { + *((char**)local_selement_address) = ""; + } + else { + *local_selement_address = NULL; + } + } + else if (trg_extf_flags & ST_ON_PTRXFER_SKIP) { + ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in skipping ptr transfer", selement, sel_analyzed, sel_stats, cb_info); + } + else { + if (trg_paired) { + ST_CB_PRINT(ST_CB_ERR, "uncaught ptr lookup for non-transferred target", selement, sel_analyzed, sel_stats, cb_info); + } + else { + ST_CB_PRINT(ST_CB_ERR, "uncaught ptr lookup for unpaired target", selement, sel_analyzed, sel_stats, cb_info); + } +#if DO_SKIP_UNPAIRED_PTR_TARGETS + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; +#else + return ENOENT; +#endif + } + + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; +} + +PRIVATE INLINE int transfer_ptr_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + const struct _magic_type *first_trg_type; + if (selement->type->type_id != MAGIC_TYPE_POINTER) { + if (selement->type->size != sizeof(void*)) { + ST_CB_PRINT(ST_CB_ERR, "wrong pointer size", selement, sel_analyzed, sel_stats, cb_info); + return EFAULT; + } + ST_CB_PRINT(ST_CB_DBG, "casting non-ptr to ptr element", selement, sel_analyzed, sel_stats, cb_info); + st_cb_selement_type_cast(MAGIC_VOID_PTR_INT_CAST_TYPE, MAGIC_VOID_PTR_INT_CAST_TYPE, selement, sel_analyzed, sel_stats, cb_info); + } + first_trg_type = MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(sel_analyzed); + if (first_trg_type == MAGIC_TYPE_NULL_ENTRY + || first_trg_type == MAGIC_TYPE_VALUE_FOUND) { + + /* NULL pointer or special value. Don't adjust value */ + return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + + } else if (!(sel_analyzed->flags & MAGIC_SEL_FOUND_VIOLATIONS)) { + /* Valid pointer found */ + if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) { + return transfer_ptr_sel_with_trg_cb(selement, sel_analyzed, sel_stats, cb_info); + } + + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + + } else if(MAGIC_STATE_FLAG(selement->sentry, MAGIC_STATE_STACK)) { + struct _magic_sentry *trg_sentry = magic_sentry_lookup_by_range(sel_analyzed->u.ptr.value, NULL); + if (trg_sentry && !strcmp(trg_sentry->name, MAGIC_ALLOC_INITIAL_STACK_NAME)) { + /* Stack pointer to initial stack area. This is common (e.g., argv). + * We can safely assume the pointer will be already correctly + * initialized in the new version and simply skip transfer. + */ + ST_CB_PRINT(ST_CB_DBG, "skipping stack ptr element pointing to initial stack area", selement, sel_analyzed, sel_stats, cb_info); + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + } + } + + /* Pointer with violations found */ + ST_CB_PRINT(ST_CB_ERR, "uncaught ptr with violations", selement, sel_analyzed, sel_stats, cb_info); +#if DO_SKIP_INVARIANTS_VIOLATIONS + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; +#else + return EFAULT; +#endif +} + +PRIVATE INLINE int transfer_struct_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + static int st_counter = 0; + unsigned parent_offset, offset; + int walk_flags, ret; + + if (selement->type->type_id != MAGIC_TYPE_UNION && selement->type->type_id != MAGIC_TYPE_STRUCT) { + ST_CB_PRINT(ST_CB_ERR, "struct transfer is only for structs and unions!", selement, sel_analyzed, sel_stats, cb_info); + return EFAULT; + } + if (selement->type->type_id == MAGIC_TYPE_STRUCT || st_counter > 0) { + return MAGIC_SENTRY_ANALYZE_CONTINUE; + } + + /* Walk the union as a struct. */ + walk_flags = cb_info->walk_flags; + cb_info->walk_flags = (MAGIC_TYPE_WALK_DEFAULT_FLAGS & (~MAGIC_TYPE_WALK_UNIONS_AS_VOID)); + st_counter++; + parent_offset = (unsigned)selement->parent_address - (unsigned)selement->sentry->address; + offset = (unsigned)selement->address - (unsigned)selement->sentry->address; + ret = magic_type_walk_flags(selement->parent_type, parent_offset, + selement->child_num, selement->type, offset, + 0, ULONG_MAX, magic_type_analyzer_cb, selement->cb_args, cb_info->walk_flags); + st_counter--; + cb_info->walk_flags = walk_flags; + if (ret != 0) { + return ret == MAGIC_TYPE_WALK_STOP ? MAGIC_SENTRY_ANALYZE_STOP : ret; + } + + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; +} + +PRIVATE INLINE int default_transfer_selement_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + /* Default handler for walkable, ptr and nonptr types. */ +#if ST_TRANSFER_IDENTITY_FOR_NO_INNER_PTRS + if (MAGIC_TYPE_FLAG(selement->type, MAGIC_TYPE_NO_INNER_PTRS)) { + /* If the type has no inner pointers, try to do raw copying. */ + if (transfer_try_raw_copy_sel_cb(selement, cb_info) == MAGIC_SENTRY_ANALYZE_SKIP_PATH) + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + } +#endif + if (selement->type->type_id == MAGIC_TYPE_UNION) { + if (!(st_policies & ST_IXFER_UNCAUGHT_UNIONS) && !MAGIC_TYPE_FLAG(selement->type, MAGIC_TYPE_NO_INNER_PTRS)) { + ST_CB_PRINT(ST_CB_ERR, "uncaught union", selement, sel_analyzed, sel_stats, cb_info); + return EFAULT; + } + else { + int level = (st_policies & ST_REPORT_UNCAUGHT_UNIONS) ? ST_CB_ERR : ST_CB_DBG; + ST_CB_PRINT(level, "uncaught union", selement, sel_analyzed, sel_stats, cb_info); + return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } + } else if (MAGIC_TYPE_IS_WALKABLE(selement->type)) { + return transfer_walkable_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } else if (selement->type->type_id == MAGIC_TYPE_POINTER) { + return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } else { + return transfer_nonptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } + + /* Not reachable. */ + ST_CB_PRINT(ST_CB_ERR, "Bug!", selement, sel_analyzed, sel_stats, cb_info); + return EINTR; +} + +PUBLIC int st_cb_transfer_sentry_default(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + char *sentry_name = selement->sentry->name; + +#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER + if (MAGIC_STATE_FLAGS(selement->sentry, MAGIC_STATE_DYNAMIC)) { + if (MAGIC_STATE_FLAG(selement->sentry, MAGIC_STATE_LIB) || MAGIC_SENTRY_IS_EXT_ALLOC(selement->sentry)) + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + } +#endif + + if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_ixfers, sentry_name)) { + ST_CB_PRINT(ST_CB_DBG, "sentry name matches ixfer", selement, sel_analyzed, sel_stats, cb_info); + return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } + + if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_cixfers, sentry_name)) { + ST_CB_PRINT(ST_CB_DBG, "sentry name matches cixfer", selement, sel_analyzed, sel_stats, cb_info); + return transfer_cond_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } + + if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_noxfers, sentry_name)) { + ST_CB_PRINT(ST_CB_DBG, "sentry name matches noxfer", selement, sel_analyzed, sel_stats, cb_info); + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + } + + if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_pxfers, sentry_name)) { + ST_CB_PRINT(ST_CB_DBG, "sentry name matches pxfer", selement, sel_analyzed, sel_stats, cb_info); + return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } + + if (MAGIC_STATE_FLAGS(selement->sentry, MAGIC_STATE_DYNAMIC | MAGIC_STATE_MAP | MAGIC_STATE_LIB)) { + struct _magic_dsentry *dsentry = MAGIC_DSENTRY_FROM_SENTRY(selement->sentry); + if (ST_DSENTRY_PARENT_NAME_MATCH_ANY(st_dsentry_lib_noxfer, dsentry->parent_name)) { + ST_CB_PRINT(ST_CB_DBG, "dsentry is a lib map and parent_name matches dsentry_lib_noxfer", selement, sel_analyzed, sel_stats, cb_info); + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + } + } + + return ST_CB_NOT_PROCESSED; +} + +PUBLIC int st_cb_transfer_typename_default(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + char *typename_key = ST_TYPE_NAME_KEY(selement->type); + if (ST_TYPE_NAME_MATCH_ANY(st_typename_ixfers, typename_key)) { + return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } + + if (ST_TYPE_NAME_MATCH_ANY(st_typename_cixfers, typename_key)) { + return transfer_cond_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } + + if (ST_TYPE_NAME_MATCH_ANY(st_typename_noxfers, typename_key)) { + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + } + + if (ST_TYPE_NAME_MATCH_ANY(st_typename_pxfers, typename_key)) { + return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } + + if (ST_TYPE_NAME_MATCH_ANY(st_typename_sxfers, typename_key)) { + return transfer_struct_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + } + + return ST_CB_NOT_PROCESSED; +} + +PUBLIC int st_cb_transfer_walkable(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + return transfer_walkable_sel_cb(selement, sel_analyzed, sel_stats, cb_info); +} + +PUBLIC int st_cb_transfer_ptr(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info); +} + +PUBLIC int st_cb_transfer_identity(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); +} + +PUBLIC int st_cb_transfer_cond_identity(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + return transfer_cond_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); +} + +PUBLIC int st_cb_transfer_nonptr(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + return transfer_nonptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info); +} + +PUBLIC int st_cb_transfer_struct(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + return transfer_struct_sel_cb(selement, sel_analyzed, sel_stats, cb_info); +} + +PUBLIC int st_cb_transfer_selement_base(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + return default_transfer_selement_sel_cb(selement, sel_analyzed, sel_stats, cb_info); +} + +PUBLIC int st_cb_transfer_selement_generic(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) +{ + return transfer_data_selement(selement, sel_analyzed, sel_stats, cb_info); +} + +/* Selement mapping functions and callbacks. */ + +PRIVATE int st_map_selement_from_sentry_cb(const struct _magic_type* parent_type, + const unsigned parent_offset, int child_num, + const struct _magic_type* type, const unsigned offset, int depth, void* cb_args) +{ + void **args_array = (void**) cb_args; + _magic_selement_t cached_selement; + _magic_selement_t *local_selement = (_magic_selement_t*) args_array[1]; + _magic_selement_t *selement = (_magic_selement_t*) args_array[0]; + struct _magic_sentry *sentry = selement->sentry; + void *address = (char*)sentry->address + offset; + void *selement_address = selement->address; + int is_trg_mapping; + struct st_cb_info *cb_info; + if ((char*) selement_address >= ((char*) address + type->size)) { + return MAGIC_TYPE_WALK_SKIP_PATH; + } + cb_info = (struct st_cb_info*) args_array[2]; + is_trg_mapping = (int) args_array[3]; + cached_selement.sentry = sentry; + cached_selement.parent_type = parent_type; + cached_selement.parent_address = (char*)sentry->address + parent_offset; + cached_selement.child_num = child_num; + cached_selement.type = type; + cached_selement.address = address; + cached_selement.depth = depth; + st_map_selement(&cached_selement, local_selement, cb_info, is_trg_mapping); + if (local_selement->type == NULL) { + return ENOENT; + } + if (address == selement_address && type == selement->type) { + return MAGIC_TYPE_WALK_STOP; + } + if (type->num_child_types == 0) { + return EINVAL; + } + local_selement->parent_type = local_selement->type; + local_selement->parent_address = local_selement->address; + return MAGIC_TYPE_WALK_CONTINUE; +} + +PRIVATE INLINE void st_map_selement_from_sentry(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct _magic_sentry *local_sentry, struct st_cb_info *cb_info, int is_trg_mapping) +{ + unsigned max_offset; + int r; + void *args_array[4]; + max_offset = (unsigned) ( (char *)cached_selement->address - (char *)cached_selement->sentry->address); + args_array[0] = cached_selement; + args_array[1] = magic_selement_from_sentry(local_sentry, local_selement); + args_array[2] = cb_info; + args_array[3] = (void*) is_trg_mapping; + r = magic_type_walk_root(cached_selement->sentry->type, 0, max_offset, st_map_selement_from_sentry_cb, (void*) args_array); + if (r < 0) { + assert(r == ENOENT); + local_selement->type = NULL; + } +} + +PRIVATE INLINE void st_map_sel_analyzed_from_target(_magic_sel_analyzed_t *cached_sel_analyzed, _magic_sel_analyzed_t *local_sel_analyzed, struct _magic_sentry *local_trg_sentry, struct _magic_function *local_trg_function, struct st_cb_info *cb_info) +{ + _magic_selement_t *csel, *lsel; + assert(local_trg_sentry || local_trg_function); + assert(cached_sel_analyzed->type_id == MAGIC_TYPE_POINTER); + assert(cached_sel_analyzed->u.ptr.first_legal_trg_type>=0); + local_sel_analyzed->type_id = cached_sel_analyzed->type_id; + local_sel_analyzed->num = cached_sel_analyzed->num; + local_sel_analyzed->flags = cached_sel_analyzed->flags; + local_sel_analyzed->u.ptr.trg_flags = local_trg_sentry ? local_trg_sentry->flags : local_trg_function->flags; + local_sel_analyzed->u.ptr.first_legal_trg_type = -1; + local_sel_analyzed->u.ptr.num_legal_trg_types = 0; + if (local_trg_function) { + assert(cached_sel_analyzed->u.ptr.num_legal_trg_types == 1); + lsel = &local_sel_analyzed->u.ptr.trg_selements[0]; + memset(lsel, 0, sizeof(_magic_selement_t)); + lsel->sentry = NULL; + lsel->type = local_trg_function->type; + lsel->address = local_trg_function->address; + local_sel_analyzed->u.ptr.num_trg_types = 1; + } + else { + int i; + void *address = NULL; + local_sel_analyzed->u.ptr.num_trg_types = 0; + for (i = cached_sel_analyzed->u.ptr.first_legal_trg_type ; i < cached_sel_analyzed->u.ptr.num_trg_types ; i++) { + _magic_trg_stats_t trg_stats = cached_sel_analyzed->u.ptr.trg_stats[i]; + if (MAGIC_SEL_ANALYZED_TRG_STATS_HAS_VIOLATIONS(trg_stats)) { + continue; + } + csel = &cached_sel_analyzed->u.ptr.trg_selements[i]; + lsel = &local_sel_analyzed->u.ptr.trg_selements[local_sel_analyzed->u.ptr.num_trg_types++]; + st_map_selement_from_sentry(csel, lsel, local_trg_sentry, cb_info, TRUE); + if (lsel->type == NULL || (address && lsel->address != address)) { + /* Unpaired selement or ambiguous local address. */ + local_sel_analyzed->u.ptr.num_trg_types = 0; + return; + } + address = lsel->address; + } + assert(local_sel_analyzed->u.ptr.num_trg_types > 0); + } +} + +PUBLIC void st_map_local_selement_from_child_num(_magic_selement_t *local_selement, struct st_cb_info *cb_info, int child_num) +{ + local_selement->child_num = child_num; + magic_selement_fill_from_parent_info(local_selement, cb_info->walk_flags); +} + +PUBLIC void st_cb_map_from_parent_array_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + int cached_num_elements, local_num_elements, is_trg_at_array_end, is_trg_at_str_end; + /* Match arrays/vectors with arrays/vectors. */ + assert(cached_selement->parent_type->type_id == MAGIC_TYPE_ARRAY || cached_selement->parent_type->type_id == MAGIC_TYPE_VECTOR); + if (local_selement->parent_type->type_id != MAGIC_TYPE_ARRAY && local_selement->parent_type->type_id != MAGIC_TYPE_VECTOR) { + local_selement->type = NULL; + return; + } + cached_num_elements = cached_selement->parent_type->num_child_types; + local_num_elements = local_selement->parent_type->num_child_types; + /* Same size or first child? We are done. */ + if (cached_num_elements == local_num_elements || local_selement->child_num == 0) { + st_map_local_selement_from_child_num(local_selement, cb_info, cached_selement->child_num); + return; + } + assert(local_num_elements > 0); + is_trg_at_str_end = FALSE; + is_trg_at_array_end = FALSE; + if (is_trg_mapping && cached_selement->child_num == cached_num_elements-1) { + is_trg_at_str_end = MAGIC_SENTRY_IS_STRING(cached_selement->sentry) || MAGIC_SENTRY_IS_STRING(local_selement->sentry); + is_trg_at_array_end = !is_trg_at_str_end; + } + if (is_trg_at_array_end && (st_policies & ST_DEFAULT_MAP_GUARD_PTRS_TO_ARRAY_END)) { + /* This should be interpreted as a target of a guard pointer pointing to the last element of an array and needs to be remapped as such. */ + st_map_local_selement_from_child_num(local_selement, cb_info, local_num_elements-1); + } + else if (is_trg_at_str_end && (st_policies & ST_DEFAULT_MAP_GUARD_PTRS_TO_STR_END)) { + /* This should be interpreted as a target of a guard pointer pointing to the last element of a string and needs to be remapped as such. */ + st_map_local_selement_from_child_num(local_selement, cb_info, local_num_elements-1); + } + else if (cached_selement->child_num >= local_num_elements) { + /* New array got truncated and this element is gone. */ + local_selement->type = NULL; + } + else { + /* New array is bigger, just keep the original position in the array. */ + st_map_local_selement_from_child_num(local_selement, cb_info, cached_selement->child_num); + } +} + +PUBLIC void st_cb_map_child_array_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + size_t cached_size = cached_selement->type->num_child_types, local_size = local_selement->type->num_child_types; + + /* Match arrays/vectors with arrays/vectors. */ + assert(cached_selement->type->type_id == MAGIC_TYPE_ARRAY || cached_selement->type->type_id == MAGIC_TYPE_VECTOR); + if (local_selement->type->type_id != MAGIC_TYPE_ARRAY && local_selement->type->type_id != MAGIC_TYPE_VECTOR) { + local_selement->type = NULL; + return; + } + + /* Varsized arrays have to be consistent across versions. */ + if (MAGIC_TYPE_FLAG(cached_selement->type, MAGIC_TYPE_VARSIZE) != MAGIC_TYPE_FLAG(local_selement->type, MAGIC_TYPE_VARSIZE)) { + local_selement->type = NULL; + return; + } + + /* Check size. */ + if (cached_size != local_size) { + int report; + int is_string = MAGIC_SENTRY_IS_STRING(cached_selement->sentry) || MAGIC_SENTRY_IS_STRING(local_selement->sentry); + if (local_size < cached_size) { + report = is_string ? (st_policies & ST_REPORT_SMALLER_STRINGS) : (st_policies & ST_REPORT_SMALLER_ARRAYS); + } + else { + report = is_string ? (st_policies & ST_REPORT_LARGER_STRINGS) : (st_policies & ST_REPORT_LARGER_ARRAYS); + } + + if (report) { + printf("st_cb_map_child_array_selement_generic: %s size found while mapping array selements:\n", local_size < cached_size ? "Smaller" : "Larger"); + MAGIC_SELEMENT_PRINT(cached_selement, MAGIC_EXPAND_TYPE_STR); printf("\n"); + MAGIC_SELEMENT_PRINT(local_selement, MAGIC_EXPAND_TYPE_STR); printf("\n"); + } + } +} + +PUBLIC void st_cb_map_from_parent_union_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + /* This should only be called in case of unions transferred as structs. */ + st_cb_map_from_parent_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); +} + +PUBLIC void st_cb_map_child_union_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + /* Match unions just like structs. */ + st_cb_map_child_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); +} + +PUBLIC void st_cb_map_from_parent_struct_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + int i; + char *cached_member_name; + /* Match struct/unions with struct/unions. */ + assert(cached_selement->parent_type->type_id == MAGIC_TYPE_STRUCT || cached_selement->parent_type->type_id == MAGIC_TYPE_UNION); + if (local_selement->parent_type->type_id != MAGIC_TYPE_STRUCT && local_selement->parent_type->type_id != MAGIC_TYPE_UNION) { + local_selement->type = NULL; + return; + } + /* Match struct/unions members by name. */ + cached_member_name = cached_selement->parent_type->member_names[cached_selement->child_num]; + for (i = 0 ; i < local_selement->parent_type->num_child_types ; i++) { + if (!strcmp(local_selement->parent_type->member_names[i], cached_member_name)) { + st_map_local_selement_from_child_num(local_selement, cb_info, i); + return; + } + } + local_selement->type = NULL; +} + +PUBLIC void st_cb_map_child_struct_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + int i, j; + const struct _magic_type *cached_type = cached_selement->type; + const struct _magic_type *local_type = local_selement->type; + assert(cached_type->type_id == MAGIC_TYPE_STRUCT || cached_type->type_id == MAGIC_TYPE_UNION); + if (local_type->type_id != MAGIC_TYPE_STRUCT && local_type->type_id != MAGIC_TYPE_UNION) { + local_selement->type = NULL; + return; + } + /* Match struct/unions by name(s). */ + if (!strcmp(cached_type->name, local_type->name)) { + return; + } + if (cached_type->num_names > 1 || local_type->num_names > 1 ) { + for (i = 0 ; i < cached_type->num_names ; i++) { + for (j = 0 ; j < local_type->num_names ; j++) { + if (!strcmp(cached_type->names[i], local_type->names[j])) { + return; + } + } + } + } + + local_selement->type = NULL; +} + +PUBLIC void st_cb_map_child_nonaggr_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + int r; + static char magic_value_buffer[32]; + + r = magic_selement_value_cast(cached_selement, local_selement, magic_value_buffer); + if (r == 0) { + return; + } + if (r < 0 && r != MAGIC_ERANGE && r != MAGIC_ESIGN) { + local_selement->type = NULL; + return; + } + if ((r == MAGIC_ERANGE && (st_policies & ST_REPORT_PRECISION_LOSS)) + || (r == MAGIC_ESIGN && (st_policies & ST_REPORT_SIGN_CHANGE))) { + _magic_selement_t converted_selement = *cached_selement; + converted_selement.address = magic_value_buffer; + converted_selement.type = local_selement->type; + printf("st_cb_map_child_nonaggr_selement_generic: %s while mapping non-aggregate selements:\n", r == MAGIC_ERANGE ? "Precision loss" : "Sign change"); + MAGIC_SELEMENT_PRINT(cached_selement, MAGIC_EXPAND_TYPE_STR); printf("\n"); + MAGIC_SELEMENT_PRINT(local_selement, MAGIC_EXPAND_TYPE_STR); printf("\n"); + printf(" - ORIGINAL VALUE: "); magic_selement_print_value(cached_selement); printf("\n"); + printf(" - MAPPED VALUE: "); magic_selement_print_value(&converted_selement); printf("\n"); + } + cached_selement->address = magic_value_buffer; +} + +PUBLIC void st_cb_map_from_parent_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + assert(cached_selement->parent_type && local_selement->parent_type); + switch(cached_selement->parent_type->type_id) { + case MAGIC_TYPE_ARRAY: + case MAGIC_TYPE_VECTOR: + st_cb_map_from_parent_array_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); + break; + + case MAGIC_TYPE_UNION: + st_cb_map_from_parent_union_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); + break; + + case MAGIC_TYPE_STRUCT: + st_cb_map_from_parent_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); + break; + + default: + st_cbs_os.panic("Invalid parent type!"); + break; + } +} + +PUBLIC void st_cb_map_child_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + assert(cached_selement->type); + if (local_selement->type == NULL) { + return; + } + if (cached_selement->type->num_child_types == 0 || cached_selement->type->type_id == MAGIC_TYPE_POINTER) { + st_cb_map_child_nonaggr_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); + return; + } + switch (cached_selement->type->type_id) { + case MAGIC_TYPE_ARRAY: + case MAGIC_TYPE_VECTOR: + st_cb_map_child_array_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); + break; + + case MAGIC_TYPE_UNION: + st_cb_map_child_union_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); + break; + + case MAGIC_TYPE_STRUCT: + st_cb_map_child_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); + break; + + default: + st_cbs_os.panic("Invalid parent type!"); + break; + } +} + + +PUBLIC void st_cb_map_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + int i; + assert(cached_selement->type->type_id != MAGIC_TYPE_FUNCTION); + for (i = 0 ; i < MAGIC_ST_TYPE_TRANS_ITERATIONS ; i++) { + if (cached_selement->parent_type) { + st_cb_map_from_parent_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); + } + st_cb_map_child_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping); + } +} + +PRIVATE INLINE void st_map_selement(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping) +{ + const struct _magic_type *cached_parent_type = cached_selement->parent_type; + const struct _magic_type *local_parent_type = local_selement->parent_type; + const struct _magic_type *cached_type = cached_selement->type; + + if (cached_parent_type) { + if (cached_parent_type == local_parent_type) { + /* Quickly propagate perfect type pairs from parents. */ + local_selement->address = (char *)local_selement->parent_address + ((char *)cached_selement->address - (char *)cached_selement->parent_address); + local_selement->type = cached_type; + return; + } + else if (ST_TYPE_IS_CACHED_COUNTERPART(cached_parent_type, local_parent_type)) { + /* Quickly propagate type pairs from parents. */ + st_map_local_selement_from_child_num(local_selement, cb_info, cached_selement->child_num); + return; + } + else { + local_selement->type = NULL; + } + } + else { + /* In case of target mapping, we don't care about compatible types. When paired types are found, add a perfect type pair to speed up subsequent lookups. */ + if (ST_TYPE_IS_CACHED_COUNTERPART(cached_type, local_selement->type)) { + if (is_trg_mapping) local_selement->type = cached_type; + return; + } + } +#if CHECK_ASR && !FORCE_SOME_UNPAIRED_TYPES + if (cb_info->init_info->flags & ST_LU_ASR) { + st_cbs_os.panic("ASR should never get here!"); + } +#endif + + st_num_type_transformations++; + st_cbs.st_cb_selement_map(cached_selement, local_selement, cb_info, is_trg_mapping); + + /* Check again for paired types and add a perfect type pair to speed up subsequent lookups in case of target mapping. */ + if (is_trg_mapping && local_selement->type != NULL && local_selement->type != cached_selement->type) { + if (ST_TYPE_IS_CACHED_COUNTERPART(cached_selement->type, local_selement->type)) { + local_selement->type = cached_selement->type; + } + } +} + +/* main functions */ + +PUBLIC int st_state_transfer(st_init_info_t *info) +{ + int r; + + /* + * Set all OS dependent callbacks first. + */ + st_setcb_os_all(&info->st_cbs_os); + +#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER + _magic_vars->fake_malloc = 1; +#endif + + r = st_init(info); + +#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER + _magic_vars->fake_malloc = 0; +#endif + + if (r != OK) { + return r; + } + + r = st_data_transfer(info); + if (r != OK) { + return r; + } + +#if ST_DEBUG_LEVEL > 0 + printf("st_state_transfer: state transfer is done, num type transformations: %u.\n", st_num_type_transformations); +#endif + + st_cleanup(info); + + return OK; +} + +PUBLIC void st_set_policies(int policies) +{ + st_policies = policies; +} + +#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX +PRIVATE void st_init_rl_index(st_init_info_t *info, + struct _magic_vars_t *magic_vars) +{ + size_t buff_size; + void *buff; + + EXEC_WITH_MAGIC_VARS( + buff_size = magic_sentry_rl_estimate_index_buff_size(0); + , magic_vars + ); + buff = st_buff_allocate(info, buff_size); + + EXEC_WITH_MAGIC_VARS( + magic_sentry_rl_build_index(buff, buff_size); + , magic_vars + ); +} + +PRIVATE void st_cleanup_rl_index(st_init_info_t *info, + struct _magic_vars_t *magic_vars) +{ + EXEC_WITH_MAGIC_VARS( + magic_sentry_rl_destroy_index(); + , magic_vars + ); +} +#endif + +#if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH +PRIVATE void st_init_sentry_hash(st_init_info_t *info, + struct _magic_vars_t *magic_vars) +{ + size_t buff_size; + void *buff; + + EXEC_WITH_MAGIC_VARS( + buff_size = magic_sentry_hash_estimate_buff_size(0); + , magic_vars + ); + buff = st_buff_allocate(info, buff_size); + + EXEC_WITH_MAGIC_VARS( + magic_sentry_hash_build(buff, buff_size); + , magic_vars + ); +} + +PRIVATE void st_cleanup_sentry_hash(st_init_info_t *info, + struct _magic_vars_t *magic_vars) +{ + EXEC_WITH_MAGIC_VARS( + magic_sentry_hash_destroy(); + , magic_vars + ); +} +#endif + +#if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH +PRIVATE void st_init_function_hash(st_init_info_t *info, + struct _magic_vars_t *magic_vars) +{ + size_t buff_size; + void *buff; + + EXEC_WITH_MAGIC_VARS( + buff_size = magic_function_hash_estimate_buff_size(0); + , magic_vars + ); + buff = st_buff_allocate(info, buff_size); + + EXEC_WITH_MAGIC_VARS( + magic_function_hash_build(buff, buff_size); + , magic_vars + ); +} + +PRIVATE void st_cleanup_function_hash(st_init_info_t *info, + struct _magic_vars_t *magic_vars) +{ + EXEC_WITH_MAGIC_VARS( + magic_function_hash_destroy(); + , magic_vars + ); +} +#endif + +PRIVATE void st_vars_clear_ptrs(struct _magic_vars_t *magic_vars) +{ +#undef __X +#define __X(x) offsetof(struct _magic_vars_t, x) + size_t offset_list[] = { ST_MAGIC_VARS_PTR_CLEAR_LIST }; +#undef __X + int i; + + for (i = 0 ; i < sizeof(offset_list) / sizeof(size_t) ; i++) + *((void **)(((char *)magic_vars) + offset_list[i])) = NULL; +} + +PUBLIC int st_init(st_init_info_t *info) +{ + int r, max_buff_sz = 0, dsentries_num; + int allow_unpaired_types = TRUE; + if (st_init_done) { + return OK; + } + if (!_magic_enabled) return ENOSYS; + st_init_done = TRUE; + + /* Ignore nested mempool dsentries for now. */ + magic_lookup_nested_dsentries = 0; + + /* Override default state transfer policies for ASR. */ + if ((info->flags & ST_LU_ASR) && st_policies == ST_POLICIES_DEFAULT) { + st_policies = ST_POLICIES_DEFAULT_TRANSFER_ASR; + } + + /* Fixup state transfer policies based on current configuration. */ +#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER + st_policies &= (~ST_DEFAULT_ALLOC_CASCADE_XFER); +#elif !defined(__MINIX) + st_policies |= ST_TRANSFER_DIRTY_ONLY; +#endif + + assert((!info->init_buff_start || (info->flags & ST_LU_NOMMAP)) && "st_init: no mmapping allowed, and no buffer is available"); + register_typenames_and_callbacks(); + + /* Transfer _magic_vars, which contain addresses of the magic variables */ + r = st_cbs_os.old_state_table_lookup(info->info_opaque, &st_remote_magic_vars); + assert( r == OK && "ERROR occurred during transfer of _magic_vars."); + /* + * Clear all pointers not explictly transferred, as they are not valid in + * the new address space. + */ + st_vars_clear_ptrs(&st_remote_magic_vars); + + /* + * Some magic_vars members do not need transfer or adjustment + * (e.g. the memory ranges). They are copied to st_cached_magic_vars + * this way. + */ + st_cached_magic_vars = st_remote_magic_vars; + + /* Transfer and adjust metadata */ + r = st_transfer_metadata_types(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts); + assert( r == OK && "ERROR occurred during transfer of type metadata."); + r = transfer_metadata_functions(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts); + assert( r == OK && "ERROR occurred during transfer of function metadata."); + r = transfer_metadata_dfunctions(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts); + assert( r == OK && "ERROR occurred during transfer of dfunction metadata."); + r = transfer_metadata_sentries(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts, &max_buff_sz); + assert( r == OK && "ERROR occurred during transfer of sentry metadata."); + r = st_transfer_metadata_dsentries(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts, &max_buff_sz, &dsentries_num); + assert( r == OK && "ERROR occurred during transfer of dsentry metadata."); + + /* Allocate buffer for data transfer */ + st_dsentry_buff = st_buff_allocate(info, max_buff_sz + sizeof(struct _magic_dsentry)); + if (!st_dsentry_buff) { + printf("st_dsentry_buff could not be allocated.\n"); + return EGENERIC; + } + st_data_buff = &st_dsentry_buff[1]; + + /* Allocate and initialize counterparts buffers. */ + st_counterparts.functions_size = st_cached_magic_vars.functions_num; + st_counterparts.functions = st_buff_allocate(info, st_counterparts.functions_size * sizeof(st_ptr_mapping)); + assert(st_counterparts.functions && "st_counterparts.functions could not be allocated."); + + st_counterparts.types_size = st_cached_magic_vars.types_num; + st_counterparts.types = st_buff_allocate(info, st_counterparts.types_size * sizeof(st_ptr_mapping)); + assert(st_counterparts.types && "st_counterparts.types could not be allocated."); + st_counterparts.ptr_types = st_buff_allocate(info, st_counterparts.types_size * sizeof(st_ptr_mapping)); + assert(st_counterparts.ptr_types && "st_counterparts.ptr_types could not be allocated."); + + st_counterparts.sentries_size = st_cached_magic_vars.sentries_num + dsentries_num; + st_counterparts.sentries = st_buff_allocate(info, st_counterparts.sentries_size * sizeof(st_ptr_mapping)); + assert(st_counterparts.sentries && "st_counterparts.sentries could not be allocated."); + st_counterparts.sentries_data = st_buff_allocate(info, st_counterparts.sentries_size * sizeof(st_ptr_mapping)); + assert(st_counterparts.sentries_data && "st_counterparts.sentries_data could not be allocated."); + +#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX + st_init_rl_index(info, &st_cached_magic_vars); +#endif + +#if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH + st_init_sentry_hash(info, &st_cached_magic_vars); + st_init_sentry_hash(info, _magic_vars); +#endif + +#if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH + st_init_function_hash(info, &st_cached_magic_vars); + st_init_function_hash(info, _magic_vars); +#endif + + /* Pair metadata entities */ + r = pair_metadata_types(info, &st_cached_magic_vars, &st_counterparts, allow_unpaired_types); + assert( r == OK && "ERROR occurred during call to pair_metadata_types()."); + r = pair_metadata_functions(info, &st_cached_magic_vars, &st_counterparts); + assert( r == OK && "ERROR occurred during call to pair_metadata_functions()."); + r = pair_metadata_sentries(info, &st_cached_magic_vars, &st_counterparts); + assert( r == OK && "ERROR occurred during call to pair_metadata_sentries()."); +#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER + r = allocate_pair_metadata_dsentries_from_raw_copy(info, &st_cached_magic_vars, &st_counterparts); + assert( r == OK && "ERROR occurred during call to allocate_pair_metadata_dsentries()."); +#else + r = allocate_pair_metadata_dsentries(info, &st_cached_magic_vars, &st_counterparts); + assert( r == OK && "ERROR occurred during call to allocate_pair_metadata_dsentries()."); +#endif + + /* Set state transfer status defaults from the predefined policies. */ + st_set_status_defaults(info); + +#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX + st_init_rl_index(info, _magic_vars); +#endif + + return OK; +} + +PRIVATE INLINE char* st_lookup_str_local_data(struct _magic_sentry *cached_sentry) +{ + void *local_data_addr; + assert(cached_sentry && MAGIC_SENTRY_IS_STRING(cached_sentry)); + ST_GET_CACHED_COUNTERPART(cached_sentry, sentries, sentries_data, local_data_addr); + assert(local_data_addr && "String data not in cache!"); + return (char*) local_data_addr; +} + +#if ST_DEBUG_DATA_TRANSFER +PRIVATE void st_print_sentities(struct _magic_vars_t *magic_vars) +{ + struct _magic_dsentry *dsentry = magic_vars->first_dsentry; + int i; + + for (i = 0 ; i < magic_vars->sentries_num ; i++) { + struct _magic_sentry *sentry = &magic_vars->sentries[i]; + ST_SENTRY_PRINT(sentry, 0); + printf("\n"); + } + + while (dsentry != NULL) { + ST_DSENTRY_PRINT(dsentry, 0); + printf("\n"); + dsentry = dsentry->next; + } + + for (i = 0 ; i < magic_vars->functions_num ; i++) { + struct _magic_function *function = &magic_vars->functions[i]; + ST_FUNCTION_PRINT(function, 0); + printf("\n"); + } +} +#endif + +PUBLIC void st_map_str_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr) +{ + struct _magic_sentry *cached_sentry = *cached_sentry_ptr; + struct _magic_sentry *local_sentry = *local_sentry_ptr; + struct _magic_sentry *sentry = cached_sentry ? cached_sentry : local_sentry; + int string_flags, match_by_name, match_by_content; + ST_CHECK_INIT(); + assert((cached_sentry == NULL) ^ (local_sentry == NULL)); + + string_flags = sentry->flags & (MAGIC_STATE_STRING|MAGIC_STATE_NAMED_STRING); + assert(string_flags & MAGIC_STATE_STRING); + match_by_name = (string_flags & MAGIC_STATE_NAMED_STRING) && (st_policies & ST_MAP_NAMED_STRINGS_BY_NAME); + match_by_content = ((string_flags & MAGIC_STATE_NAMED_STRING) && (st_policies & ST_MAP_NAMED_STRINGS_BY_CONTENT)) + || (!(string_flags & MAGIC_STATE_NAMED_STRING) && (st_policies & ST_MAP_STRINGS_BY_CONTENT)); + if (match_by_name) { + /* Pretend it's a regular sentry and match by name */ + sentry->flags &= ~string_flags; + st_map_sentries(cached_sentry_ptr, local_sentry_ptr); + sentry->flags |= string_flags; + if (*cached_sentry_ptr && *local_sentry_ptr) { + /* Found by name. */ + return; + } + } + if (!match_by_content) { + /* No match. */ + return; + } + if (cached_sentry) { + EXEC_WITH_MAGIC_VARS( + local_sentry = magic_sentry_lookup_by_string(st_lookup_str_local_data(cached_sentry)); + , st_local_magic_vars_ptr + ); + } + else { + int i; + for(i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) { + struct _magic_sentry *sentry = &st_cached_magic_vars.sentries[i]; + if (MAGIC_SENTRY_IS_STRING(sentry) && !strcmp(st_lookup_str_local_data(sentry), (char*)local_sentry->address)) { + cached_sentry = sentry; + break; + } + } + } + *cached_sentry_ptr = cached_sentry; + *local_sentry_ptr = local_sentry; +} + +PUBLIC void st_map_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr) +{ + struct _magic_sentry *cached_sentry = *cached_sentry_ptr; + struct _magic_sentry *local_sentry = *local_sentry_ptr; + struct _magic_dsentry *cached_dsentry = cached_sentry ? (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC) ? MAGIC_DSENTRY_FROM_SENTRY(cached_sentry) : NULL) : NULL; + struct _magic_dsentry *local_dsentry = local_sentry ? (MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC) ? MAGIC_DSENTRY_FROM_SENTRY(local_sentry) : NULL) : NULL; + ST_CHECK_INIT(); + assert((cached_sentry == NULL) ^ (local_sentry == NULL)); + + if ((cached_sentry && MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_STRING)) + || (local_sentry && MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_STRING))) { + st_map_str_sentries(cached_sentry_ptr, local_sentry_ptr); + return; + } + else if (cached_sentry) { + EXEC_WITH_MAGIC_VARS( + local_sentry = magic_sentry_lookup_by_name(cached_dsentry ? cached_dsentry->parent_name : "", cached_sentry->name, cached_dsentry ? cached_dsentry->site_id : 0, NULL); + , st_local_magic_vars_ptr + ); + assert(!local_sentry || MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC) == MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC)); + } + else { + EXEC_WITH_MAGIC_VARS( + cached_sentry = magic_sentry_lookup_by_name(local_dsentry ? local_dsentry->parent_name : "", local_sentry->name, local_dsentry ? local_dsentry->site_id : 0, NULL); + , &st_cached_magic_vars + ); + assert(!cached_sentry || MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC) == MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)); + } + *cached_sentry_ptr = cached_sentry; + *local_sentry_ptr = local_sentry; +} + +PRIVATE struct _magic_sentry *st_lookup_cached_sentry(struct _magic_sentry *local_sentry) +{ + int i; + struct _magic_dsentry *cached_dsentry; + assert(local_sentry); + + for (i = 0 ; i < st_counterparts.sentries_size ; i++) { + if (st_counterparts.sentries[i].counterpart == local_sentry) { + break; + } + } + if (i >= st_counterparts.sentries_size) { + return NULL; + } + if (i < st_cached_magic_vars.sentries_num) { + return &st_cached_magic_vars.sentries[i]; + } + i -= st_cached_magic_vars.sentries_num; + cached_dsentry = st_cached_magic_vars.first_dsentry; + assert(i >= 0); + assert(cached_dsentry); + while (i > 0) { + cached_dsentry = cached_dsentry->next; + assert(cached_dsentry); + i--; + } + return MAGIC_DSENTRY_TO_SENTRY(cached_dsentry); +} + +PUBLIC void st_lookup_sentry_pair(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr) +{ + struct _magic_sentry *cached_sentry = *cached_sentry_ptr; + struct _magic_sentry *local_sentry = *local_sentry_ptr; + ST_CHECK_INIT(); + assert((cached_sentry == NULL) ^ (local_sentry == NULL)); + + if (cached_sentry) { + ST_GET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry); + } + else if (MAGIC_SENTRY_IS_STRING(local_sentry)) { + /* strings are special, they may have multiple local duplicates */ + struct _magic_sentry *csentry = NULL, *lsentry = NULL; + st_map_str_sentries(&csentry, &local_sentry); + if (csentry) { + st_lookup_sentry_pair(&csentry, &lsentry); + if (lsentry) { + cached_sentry = csentry; + } + } + } + else { + cached_sentry = st_lookup_cached_sentry(local_sentry); + } + *cached_sentry_ptr = cached_sentry; + *local_sentry_ptr = local_sentry; +} + +PRIVATE INLINE void st_unpair_local_alloc_sentry(struct _magic_sentry *local_sentry) +{ + if (st_policies & ST_ON_ALLOC_UNPAIR_ERROR) { + st_cbs_os.panic("st_unpair_local_alloc_sentry: Error: attempting to unpair a local alloc sentry!"); + } + else if (st_policies & ST_ON_ALLOC_UNPAIR_DEALLOCATE) { + deallocate_local_dsentry(MAGIC_DSENTRY_FROM_SENTRY(local_sentry)); + } +} + +PUBLIC void st_add_sentry_pair(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry) +{ + ST_CHECK_INIT(); + assert(cached_sentry || local_sentry); + + if (local_sentry) { + struct _magic_sentry *csentry = NULL; + st_lookup_sentry_pair(&csentry, &local_sentry); + if (csentry) { + ST_SET_CACHED_COUNTERPART(csentry, sentries, sentries, NULL); + } + if (!cached_sentry && MAGIC_SENTRY_IS_ALLOC(local_sentry)) { + st_unpair_local_alloc_sentry(local_sentry); + } + } + if (cached_sentry) { + struct _magic_sentry *lsentry = NULL; + st_lookup_sentry_pair(&cached_sentry, &lsentry); + if (lsentry && MAGIC_SENTRY_IS_ALLOC(lsentry)) { + st_unpair_local_alloc_sentry(lsentry); + } + ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry); + } +} + +PUBLIC int st_add_sentry_pair_alloc_by_dsindex(st_init_info_t *info, struct _magic_sentry *cached_sentry, struct _magic_dsindex *local_dsindex, int num_elements, const union __alloc_flags *p_alloc_flags) +{ + int r; + struct _magic_dsentry *local_dsentry; + ST_CHECK_INIT(); + assert(cached_sentry); + + if (!local_dsindex) { + st_add_sentry_pair(cached_sentry, NULL); + return OK; + } + + r = allocate_local_dsentry(info, local_dsindex, num_elements, MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_TYPE_SIZE_MISMATCH), p_alloc_flags, &local_dsentry, NULL, MAGIC_PTR_TO_DSENTRY(cached_sentry->address)); + if (r != OK) { + return r; + } + st_add_sentry_pair(cached_sentry, MAGIC_DSENTRY_TO_SENTRY(local_dsentry)); + return OK; +} + +PUBLIC void st_map_functions(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr) +{ + struct _magic_function *cached_function = *cached_function_ptr; + struct _magic_function *local_function = *local_function_ptr; + ST_CHECK_INIT(); + assert((cached_function == NULL) ^ (local_function == NULL)); + + if (cached_function) { + EXEC_WITH_MAGIC_VARS( + local_function = magic_function_lookup_by_name(NULL, cached_function->name); + , st_local_magic_vars_ptr + ); + } + else { + EXEC_WITH_MAGIC_VARS( + cached_function = magic_function_lookup_by_name(NULL, local_function->name); + , &st_cached_magic_vars + ); + } + *cached_function_ptr = cached_function; + *local_function_ptr = local_function; +} + +PUBLIC void st_lookup_function_pair(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr) +{ + struct _magic_function *cached_function = *cached_function_ptr; + struct _magic_function *local_function = *local_function_ptr; + int i; + ST_CHECK_INIT(); + assert((cached_function == NULL) ^ (local_function == NULL)); + + if (cached_function) { + if (cached_function->id - 1 >= st_counterparts.functions_size) { + /* + * Try to check if this is a function + * from an external shared object. + * XXX: The number of dfunctions can be quite large, + * so this needs to be done more efficiently. + */ + struct _magic_dfunction *dfunc; + struct _magic_function *func; + MAGIC_DFUNCTION_FUNC_ITER(_magic_vars->first_dfunction, dfunc, func, + if (func->address == cached_function->address) { + local_function = func; + break; + } + ); + assert(local_function != NULL && "No counterpart found for function."); + } else { + ST_GET_CACHED_COUNTERPART(cached_function, functions, functions, local_function); + } + } + else { + assert(st_counterparts.functions_size == st_cached_magic_vars.functions_num); + for(i = 0 ; i < st_counterparts.functions_size ; i++) { + if(st_counterparts.functions[i].counterpart == local_function) { + cached_function = &st_cached_magic_vars.functions[i]; + break; + } + } + } + *cached_function_ptr = cached_function; + *local_function_ptr = local_function; +} + +PUBLIC void st_add_function_pair(struct _magic_function *cached_function, struct _magic_function *local_function) +{ + ST_CHECK_INIT(); + assert(cached_function || local_function); + + if (local_function) { + struct _magic_function *cfunction = NULL; + st_lookup_function_pair(&cfunction, &local_function); + if (cfunction) { + ST_SET_CACHED_COUNTERPART(cfunction, functions, functions, NULL); + } + } + if (cached_function) { + ST_SET_CACHED_COUNTERPART(cached_function, functions, functions, local_function); + } +} + +PUBLIC int st_sentry_equals(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry) +{ + char *cached_parent_name = "", *local_parent_name = ""; + int cached_flags = MAGIC_STATE_FLAGS_TO_NONEXTF(cached_sentry->flags) & (~MAGIC_STATE_ADDR_NOT_TAKEN); + int local_flags = MAGIC_STATE_FLAGS_TO_NONEXTF(local_sentry->flags) & (~MAGIC_STATE_ADDR_NOT_TAKEN); + if (cached_flags != local_flags) { + return FALSE; + } + if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_STRING)) { + return !strcmp(st_lookup_str_local_data(cached_sentry), (char*)local_sentry->address); + } + if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)) { + cached_parent_name = MAGIC_DSENTRY_FROM_SENTRY(cached_sentry)->parent_name; + local_parent_name = MAGIC_DSENTRY_FROM_SENTRY(local_sentry)->parent_name; + } + if (strcmp(cached_sentry->name, local_sentry->name) || strcmp(cached_parent_name, local_parent_name)) { + return FALSE; + } + return magic_type_compatible(cached_sentry->type, local_sentry->type, MAGIC_TYPE_COMPARE_ALL); +} + +PUBLIC int st_function_equals(struct _magic_function *cached_function, struct _magic_function *local_function) +{ + if (MAGIC_STATE_FLAGS_TO_NONEXTF(local_function->flags) != MAGIC_STATE_FLAGS_TO_NONEXTF(cached_function->flags)) { + return FALSE; + } + return !strcmp(cached_function->name, local_function->name); +} + +PUBLIC void st_print_sentry_diff(st_init_info_t *info, struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry, int raw_diff, int print_changed) +{ + int is_paired_sentry; + ST_CHECK_INIT(); + + if (!cached_sentry || !local_sentry) { + if (raw_diff) { + st_map_sentries(&cached_sentry, &local_sentry); + } + else { + st_lookup_sentry_pair(&cached_sentry, &local_sentry); + } + } + is_paired_sentry = (cached_sentry != NULL && local_sentry != NULL); + if (is_paired_sentry && st_sentry_equals(cached_sentry, local_sentry)) { + return; + } + if (is_paired_sentry && !print_changed) { + return; + } + if (cached_sentry) { + printf("-"); ST_SENTRY_PRINT(cached_sentry, MAGIC_EXPAND_TYPE_STR); printf("\n"); + } + if (local_sentry) { + printf("+"); ST_SENTRY_PRINT(local_sentry, MAGIC_EXPAND_TYPE_STR); printf("\n"); + } + printf("\n"); +} + +PUBLIC void st_print_function_diff(st_init_info_t *info, struct _magic_function *cached_function, struct _magic_function *local_function, int raw_diff, int print_changed) +{ + int is_paired_function; + ST_CHECK_INIT(); + + if (!cached_function || !local_function) { + if (raw_diff) { + st_map_functions(&cached_function, &local_function); + } + else { + st_lookup_function_pair(&cached_function, &local_function); + } + } + is_paired_function = (cached_function != NULL && local_function != NULL); + if (is_paired_function && st_function_equals(cached_function, local_function)) { + return; + } + if (is_paired_function && !print_changed) { + return; + } + if (cached_function) { + printf("-"); ST_FUNCTION_PRINT(cached_function, MAGIC_EXPAND_TYPE_STR); printf("\n"); + } + if (local_function) { + printf("+"); ST_FUNCTION_PRINT(local_function, MAGIC_EXPAND_TYPE_STR); printf("\n"); + } + printf("\n"); +} + +PUBLIC void st_print_sentries_diff(st_init_info_t *info, int raw_diff, int print_changed) +{ + int i; + ST_CHECK_INIT(); + + for (i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) { + struct _magic_sentry *cached_sentry = &st_cached_magic_vars.sentries[i]; + st_print_sentry_diff(info, cached_sentry, NULL, raw_diff, print_changed); + } + + print_changed = FALSE; + for (i = 0 ; i < st_local_magic_vars_ptr->sentries_num ; i++) { + struct _magic_sentry *local_sentry = &st_local_magic_vars_ptr->sentries[i]; + st_print_sentry_diff(info, NULL, local_sentry, raw_diff, print_changed); + } +} + +PUBLIC void st_print_dsentries_diff(st_init_info_t *info, int raw_diff, int print_changed) +{ + struct _magic_dsentry *dsentry; + ST_CHECK_INIT(); + + dsentry = st_cached_magic_vars.first_dsentry; + while (dsentry != NULL) { + struct _magic_sentry *cached_sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry); + st_print_sentry_diff(info, cached_sentry, NULL, raw_diff, print_changed); + dsentry = dsentry->next; + } + + dsentry = st_local_magic_vars_ptr->first_dsentry; + print_changed = FALSE; + while (dsentry != NULL) { + struct _magic_sentry *local_sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry); + st_print_sentry_diff(info, NULL, local_sentry, raw_diff, print_changed); + dsentry = dsentry->next; + } +} + +PUBLIC void st_print_functions_diff(st_init_info_t *info, int raw_diff, int print_changed) +{ + int i; + ST_CHECK_INIT(); + + for(i = 0 ; i < st_cached_magic_vars.functions_num ; i++) { + struct _magic_function *cached_function = &st_cached_magic_vars.functions[i]; + st_print_function_diff(info, cached_function, NULL, raw_diff, print_changed); + } + + print_changed = FALSE; + for (i = 0 ; i < st_local_magic_vars_ptr->functions_num ; i++) { + struct _magic_function *local_function = &st_local_magic_vars_ptr->functions[i]; + st_print_function_diff(info, NULL, local_function, raw_diff, print_changed); + } +} + +PUBLIC void st_print_state_diff(st_init_info_t *info, int raw_diff, int print_changed) +{ + ST_CHECK_INIT(); + + printf("Index: sentries\n"); + printf("===================================================================\n"); + st_print_sentries_diff(info, raw_diff, print_changed); + + printf("\nIndex: dsentries\n"); + printf("===================================================================\n"); + st_print_dsentries_diff(info, raw_diff, print_changed); + + printf("\nIndex: functions\n"); + printf("===================================================================\n"); + st_print_functions_diff(info, raw_diff, print_changed); + printf("\n"); +} + +PUBLIC int st_data_transfer(st_init_info_t *info) +{ + struct _magic_dsentry *dsentry; + int i, r; + int sentry_transferred; +#if ST_DEBUG_DATA_TRANSFER + int counter = 1; +#endif + ST_CHECK_INIT(); + + /* Check unpaired sentries. */ + for (i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) { + struct _magic_sentry *sentry = &st_cached_magic_vars.sentries[i]; + int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries); + if (!is_paired_sentry) { + r = check_unpaired_sentry(info, sentry); + if (r != OK) { + return r; + } + } + } + + /* Check unpaired dsentries. */ + dsentry = st_cached_magic_vars.first_dsentry; + while (dsentry != NULL) { + struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry); + int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries); + if (!is_paired_sentry) { + r = check_unpaired_sentry(info, sentry); + if (r != OK) { + return r; + } + } + dsentry = dsentry->next; + } + + /* Data transfer. */ + do { + sentry_transferred = 0; + +#if ST_DEBUG_DATA_TRANSFER + printf("st_data_transfer: Round %d\n", counter++); + st_print_sentities(&st_cached_magic_vars); +#endif + + /* process sentries */ +#if ST_DEBUG_LEVEL > 0 + printf("st_data_transfer: processing sentries\n"); +#endif + for(i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) { + struct _magic_sentry *sentry = &st_cached_magic_vars.sentries[i]; + int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries); + int sentry_needs_transfer = MAGIC_STATE_EXTF_GET(sentry, ST_NEEDS_TRANSFER | ST_TRANSFER_DONE) == ST_NEEDS_TRANSFER; + if (sentry_needs_transfer && is_paired_sentry) { + r = transfer_data_sentry(info, sentry); + if (r != OK) { + return r; + } + sentry_transferred = 1; + } + } + + /* process dsentries */ +#if ST_DEBUG_LEVEL > 0 + printf("st_data_transfer: processing dsentries\n"); +#endif + dsentry = st_cached_magic_vars.first_dsentry; + while (dsentry != NULL) { + struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry); + int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries); + int sentry_needs_transfer = MAGIC_STATE_EXTF_GET(sentry, ST_NEEDS_TRANSFER | ST_TRANSFER_DONE) == ST_NEEDS_TRANSFER; + if (sentry_needs_transfer && is_paired_sentry) { + r = transfer_data_sentry(info, sentry); + if (r != OK) { + return r; + } + sentry_transferred = 1; + } + dsentry = dsentry->next; + } + + } while(sentry_transferred); + + return OK; +} + +PRIVATE INLINE void st_set_transfer_status(int status_flags, int status_op, + struct _magic_sentry *cached_sentry, struct _magic_function *cached_function) +{ +#define __st_set_transfer_status(X) \ + switch(status_op) { \ + case ST_OP_NONE: \ + return; \ + break; \ + case ST_OP_ADD: \ + MAGIC_STATE_EXTF_ADD(X, status_flags); \ + break; \ + case ST_OP_DEL: \ + MAGIC_STATE_EXTF_DEL(X, status_flags); \ + break; \ + case ST_OP_SET: \ + MAGIC_STATE_EXTF_SET(X, status_flags); \ + break; \ + case ST_OP_CLEAR: \ + MAGIC_STATE_EXTF_CLEAR(X); \ + break; \ + default: \ + st_cbs_os.panic("Invalid operation!"); \ + break; \ + } \ + + if (cached_sentry) { + __st_set_transfer_status(cached_sentry); + } + else { + assert(cached_function); + __st_set_transfer_status(cached_function); + } +} + +PUBLIC void st_set_unpaired_types_ratios(float unpaired_types_ratio, + float unpaired_struct_types_ratio) +{ + st_unpaired_types_ratio = unpaired_types_ratio; + st_unpaired_struct_types_ratio = unpaired_struct_types_ratio; +} + +PUBLIC void st_set_status_defaults(st_init_info_t *info) +{ + int match_all = ~0, skip_none = 0; + int skip_state_flags = (st_policies & ST_DEFAULT_SKIP_STACK) ? MAGIC_STATE_STACK : 0; + + if (!(st_policies & ST_DEFAULT_TRANSFER_NONE)) { + /* + * Transfer all the (d)sentries by default. Skip stack dsentries when + * requested. In that case, stack dsentries won't be transferred and an + * error will be raised on stack pointer transfer. + */ + st_set_status_by_state_flags(ST_NEEDS_TRANSFER, ST_OP_SET, + match_all, skip_state_flags); + if (st_policies & ST_DEFAULT_ALLOC_CASCADE_XFER) { + /* + * If requested, mark non-stack dsentries for cascade transfer + * instead of regular transfer. + */ + st_set_status_by_state_flags(ST_ON_PTRXFER_CASCADE, ST_OP_SET, + MAGIC_STATE_HEAP | MAGIC_STATE_MAP, skip_none); + } + } + else { + /* + * Don't transfer any (d)sentries by default. Mark all the (d)sentries + * for cascade transfer (except for stack dsentries when requested). + */ + st_set_status_by_state_flags(ST_ON_PTRXFER_CASCADE, ST_OP_SET, + match_all, skip_state_flags); + } + + /* + * Always transfer all immutable objects. + */ + st_set_status_by_state_flags(ST_NEEDS_TRANSFER, ST_OP_SET, + MAGIC_STATE_IMMUTABLE, skip_none); + + /* + * If requested, mark library state dsentries as already transferred too. + */ + if (st_policies & ST_DEFAULT_SKIP_LIB_STATE) { + st_set_status_by_state_flags(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE, + ST_OP_ADD, MAGIC_STATE_LIB, skip_none); + } + + /* + * In addition, mark functions, out-of-band/string sentries + * and shared dsentries as already transferred. + */ + st_set_status_by_state_flags(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE, + ST_OP_ADD, MAGIC_STATE_TEXT | MAGIC_STATE_OUT_OF_BAND | + MAGIC_STATE_STRING | MAGIC_STATE_CONSTANT | MAGIC_STATE_SHM, skip_none); + + /* + * Finally, if we only want to transfer dirty sentries, mark all the other ones + * as already transferred. + */ + if (st_policies & ST_TRANSFER_DIRTY_ONLY) { + st_set_status_by_state_flags(ST_TRANSFER_DONE, ST_OP_ADD, match_all, MAGIC_STATE_DIRTY_PAGE); + } + +#if DO_SKIP_ENVIRON_HACK + st_set_status_by_name(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE, + ST_OP_ADD, NULL, "__environ", MAGIC_DSENTRY_SITE_ID_NULL); + st_set_status_by_name(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE, + ST_OP_ADD, NULL, "stderr", MAGIC_DSENTRY_SITE_ID_NULL); +#endif +} + +PUBLIC void st_set_status_by_state_flags(int status_flags, int status_op, + int match_state_flags, int skip_state_flags) +{ + struct _magic_dsentry *dsentry = st_cached_magic_vars.first_dsentry; + int i; + int candidate_sentry_flags = MAGIC_STATE_DATA | MAGIC_STATE_STRING | MAGIC_STATE_CONSTANT | MAGIC_STATE_ADDR_NOT_TAKEN; + int candidate_function_flags = MAGIC_STATE_TEXT; + int candidate_dsentry_flags = ~(candidate_sentry_flags | candidate_function_flags); + ST_CHECK_INIT(); + + /* process sentries */ + if (match_state_flags & candidate_sentry_flags) { + for (i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) { + int state_flags = st_cached_magic_vars.sentries[i].flags; + if ((state_flags & match_state_flags) && !(state_flags & skip_state_flags)) { + st_set_transfer_status(status_flags, status_op, &st_cached_magic_vars.sentries[i], NULL); + } + } + } + + /* process dsentries */ + if (match_state_flags & candidate_dsentry_flags) { + while (dsentry != NULL) { + int state_flags = dsentry->sentry.flags; + if ((state_flags & match_state_flags) && !(state_flags & skip_state_flags)) { + st_set_transfer_status(status_flags, status_op, MAGIC_DSENTRY_TO_SENTRY(dsentry), NULL); + } + dsentry = dsentry->next; + } + } + + /* process functions */ + if (match_state_flags & candidate_function_flags) { + for (i = 0 ; i < st_cached_magic_vars.functions_num ; i++) { + int state_flags = st_cached_magic_vars.functions[i].flags; + if ((state_flags & match_state_flags) && !(state_flags & skip_state_flags)) { + st_set_transfer_status(status_flags, status_op, NULL, &st_cached_magic_vars.functions[i]); + } + } + } +} + +PUBLIC int st_set_status_by_function_ids(int status_flags, int status_op, _magic_id_t *ids) +{ + int r, i = 0; + while (ids[i] != 0) { + r = st_set_status_by_function_id(status_flags, status_op, ids[i]); + if (r != OK) { + return r; + } + i++; + } + return OK; +} + +PUBLIC int st_set_status_by_sentry_ids(int status_flags, int status_op, _magic_id_t *ids) +{ + int r, i=0; + while (ids[i] != 0) { + r = st_set_status_by_sentry_id(status_flags, status_op, ids[i]); + if (r != OK) { + return r; + } + i++; + } + return OK; +} + +PUBLIC int st_set_status_by_names(int status_flags, int status_op, + char **parent_names, char **names, _magic_id_t *dsentry_site_ids) +{ + int r, i = 0; + while (names[i] != NULL) { + r = st_set_status_by_name(status_flags, status_op, + parent_names ? parent_names[i] : NULL, names[i], + dsentry_site_ids ? dsentry_site_ids[i] : + MAGIC_DSENTRY_SITE_ID_NULL); + if (r != OK) { + return r; + } + i++; + } + return OK; +} + +PUBLIC int st_set_status_by_local_addrs(int status_flags, int status_op, + void **addrs) +{ + int r, i=0; + while (addrs[i] != NULL) { + r = st_set_status_by_local_addr(status_flags, status_op, addrs[i]); + if (r != OK) { + return r; + } + i++; + } + return OK; +} + +PUBLIC void st_set_status_by_sentry(int status_flags, int status_op, + void *cached_sentry) +{ + ST_CHECK_INIT(); + + st_set_transfer_status(status_flags, status_op, + (struct _magic_sentry*) cached_sentry, NULL); +} + +PUBLIC void st_set_status_by_function(int status_flags, int status_op, + void *cached_function) +{ + ST_CHECK_INIT(); + + st_set_transfer_status(status_flags, status_op, + NULL, (struct _magic_function*) cached_function); +} + +PUBLIC int st_set_status_by_name(int status_flags, int status_op, + char *parent_name, char *name, _magic_id_t dsentry_site_id) +{ + struct _magic_sentry *cached_sentry = NULL; + struct _magic_function *cached_function = NULL; + ST_CHECK_INIT(); + + EXEC_WITH_MAGIC_VARS( + cached_sentry = magic_sentry_lookup_by_name(parent_name ? parent_name : "", name, dsentry_site_id, NULL); + if (!cached_sentry) { + cached_function = magic_function_lookup_by_name(parent_name, name); + } + , &st_cached_magic_vars + ); + if (!cached_sentry && !cached_function) { + return ENOENT; + } + st_set_transfer_status(status_flags, status_op, cached_sentry, cached_function); + if (cached_sentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) { + struct _magic_dsentry *prev_dsentry, *dsentry, *next_dsentry = MAGIC_DSENTRY_NEXT(MAGIC_DSENTRY_FROM_SENTRY(cached_sentry)); + struct _magic_sentry* sentry; + /* + * Alloc sentries may have multiple instances with the same name. + * Use the site_id to distinguish between them. + */ + assert(parent_name && name); + MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(next_dsentry, prev_dsentry, dsentry, sentry, + parent_name, name, dsentry_site_id, + st_set_transfer_status(status_flags, status_op, sentry, NULL); + ); + } + return OK; +} + +PUBLIC int st_set_status_by_function_id(int status_flags, int status_op, + _magic_id_t id) +{ + struct _magic_function *cached_function = NULL; + ST_CHECK_INIT(); + + EXEC_WITH_MAGIC_VARS( + cached_function = magic_function_lookup_by_id(id, NULL); + , &st_cached_magic_vars + ); + + if (!cached_function) { + return ENOENT; + } + + st_set_transfer_status(status_flags, status_op, NULL, cached_function); + return OK; +} + +PUBLIC int st_set_status_by_sentry_id(int status_flags, int status_op, + _magic_id_t id) +{ + struct _magic_sentry *cached_sentry = NULL; + ST_CHECK_INIT(); + + EXEC_WITH_MAGIC_VARS( + cached_sentry = magic_sentry_lookup_by_id(id, NULL); + , &st_cached_magic_vars + ); + + if (!cached_sentry) { + return ENOENT; + } + + st_set_transfer_status(status_flags, status_op, cached_sentry, NULL); + return OK; +} + +PUBLIC int st_set_status_by_local_addr(int status_flags, int status_op, + void *addr) +{ + char *parent_name, *name; + _magic_id_t dsentry_site_id = MAGIC_DSENTRY_SITE_ID_NULL; + struct _magic_sentry *sentry = NULL; + struct _magic_function *function = NULL; + ST_CHECK_INIT(); + + sentry = magic_sentry_lookup_by_addr(addr, NULL); + if (!sentry) { + function = magic_function_lookup_by_addr(addr, NULL); + } + if (sentry && !MAGIC_STATE_FLAG(sentry, MAGIC_STATE_DYNAMIC)) { + name = sentry->name; + parent_name = MAGIC_SENTRY_PARENT(sentry); + dsentry_site_id = MAGIC_SENTRY_SITE_ID(sentry); + } + else if (function && !MAGIC_STATE_FLAG(function, MAGIC_STATE_DYNAMIC)) { + name = function->name; + parent_name = MAGIC_FUNCTION_PARENT(function); + } + else { + return ENOENT; + } + st_set_status_by_name(status_flags, status_op, parent_name, name, dsentry_site_id); + return OK; +} + +PUBLIC int st_pair_by_function_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op) +{ + int r, i=0; + ST_CHECK_INIT(); + + while (cached_ids[i] != 0) { + assert(local_ids[i] != 0); + r = st_pair_by_function_id(cached_ids[i], local_ids[i], status_flags, status_op); + if (r != OK) { + return r; + } + i++; + } + return OK; +} + +PUBLIC int st_pair_by_sentry_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op) +{ + int r, i=0; + ST_CHECK_INIT(); + + while (cached_ids[i] != 0) { + assert(local_ids[i] != 0); + r = st_pair_by_sentry_id(cached_ids[i], local_ids[i], status_flags, status_op); + if (r != OK) { + return r; + } + i++; + } + return OK; +} + +PUBLIC int st_pair_by_names(char **cached_parent_names, char **cached_names, + char **local_parent_names, char **local_names, _magic_id_t *dsentry_site_ids, + int status_flags, int status_op) +{ + int r, i=0; + while (cached_names[i] != NULL) { + assert(local_names[i]); + r = st_pair_by_name(cached_parent_names ? cached_parent_names[i] : NULL, cached_names[i], + local_parent_names ? local_parent_names[i] : NULL, local_names[i], + dsentry_site_ids ? dsentry_site_ids[i] : MAGIC_DSENTRY_SITE_ID_NULL, + status_flags, status_op); + if (r != OK) { + return r; + } + i++; + } + return OK; +} + +PUBLIC void st_pair_by_sentry(void *cached_sentry, void *local_sentry, int status_flags, int status_op) +{ + ST_CHECK_INIT(); + + st_add_sentry_pair(cached_sentry, local_sentry); + if (cached_sentry) { + st_set_status_by_sentry(status_flags, status_op, cached_sentry); + } +} + +PUBLIC void st_pair_by_function(void *cached_function, void* local_function, int status_flags, int status_op) +{ + ST_CHECK_INIT(); + + st_add_function_pair(cached_function, local_function); + if (cached_function) { + st_set_status_by_function(status_flags, status_op, cached_function); + } +} + +PUBLIC int st_pair_alloc_by_dsindex(st_init_info_t *info, void *cached_sentry, void *local_dsindex, int num_elements, const union __alloc_flags *p_alloc_flags, int status_flags, int status_op) +{ + int r; + ST_CHECK_INIT(); + + r = st_add_sentry_pair_alloc_by_dsindex(info, cached_sentry, local_dsindex, num_elements, p_alloc_flags); + if (r != OK) { + return r; + } + if (cached_sentry) { + st_set_status_by_sentry(status_flags, status_op, cached_sentry); + } + return OK; +} + +PUBLIC int st_pair_by_function_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op) +{ + struct _magic_function *cached_function = NULL, *local_function = NULL; + ST_CHECK_INIT(); + assert(cached_id || local_id); + + if (cached_id) { + EXEC_WITH_MAGIC_VARS( + cached_function = magic_function_lookup_by_id(cached_id, NULL); + , &st_cached_magic_vars + ); + if (!cached_function) { + return ENOENT; + } + } + if (local_id) { + EXEC_WITH_MAGIC_VARS( + local_function = magic_function_lookup_by_id(local_id, NULL); + , st_local_magic_vars_ptr + ); + if (!local_function) { + return ENOENT; + } + } + + st_pair_by_function(cached_function, local_function, status_flags, status_op); + return OK; +} + +PUBLIC int st_pair_by_sentry_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op) +{ + struct _magic_sentry *cached_sentry = NULL, *local_sentry = NULL; + ST_CHECK_INIT(); + assert(cached_id || local_id); + + if (cached_id) { + EXEC_WITH_MAGIC_VARS( + cached_sentry = magic_sentry_lookup_by_id(cached_id, NULL); + , &st_cached_magic_vars + ); + if (!cached_sentry) { + return ENOENT; + } + } + if (local_id) { + EXEC_WITH_MAGIC_VARS( + local_sentry = magic_sentry_lookup_by_id(local_id, NULL); + , st_local_magic_vars_ptr + ); + if (!local_sentry) { + return ENOENT; + } + } + + st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op); + return OK; +} + +PUBLIC int st_pair_by_name(char *cached_parent_name, char *cached_name, + char *local_parent_name, char *local_name, _magic_id_t dsentry_site_id, + int status_flags, int status_op) +{ + struct _magic_function *cached_function = NULL, *local_function = NULL; + struct _magic_sentry *cached_sentry = NULL, *local_sentry = NULL; + ST_CHECK_INIT(); + assert(cached_name || local_name); + + if (cached_name) { + EXEC_WITH_MAGIC_VARS( + cached_sentry = magic_sentry_lookup_by_name(cached_parent_name ? cached_parent_name : "", cached_name, dsentry_site_id, NULL); + if (cached_sentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) { + return EINVAL; + } + if (!cached_sentry) { + cached_function = magic_function_lookup_by_name(NULL, cached_name); + } + , &st_cached_magic_vars + ); + if (!cached_sentry && !cached_function) { + return ENOENT; + } + } + if (local_name) { + EXEC_WITH_MAGIC_VARS( + if (!cached_function) { + local_sentry = magic_sentry_lookup_by_name(local_parent_name ? local_parent_name : "", local_name, dsentry_site_id, NULL); + if (local_sentry && MAGIC_SENTRY_IS_ALLOC(local_sentry)) { + return EINVAL; + } + } + if (!cached_sentry && !local_sentry) { + local_function = magic_function_lookup_by_name(NULL, local_name); + } + , st_local_magic_vars_ptr + ); + if (!local_sentry && !local_function) { + return ENOENT; + } + } + if (cached_function || local_function) { + assert(!cached_sentry && !local_sentry); + st_pair_by_function(cached_function, local_function, status_flags, status_op); + return OK; + } + assert(cached_sentry || local_sentry); + st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op); + return OK; +} + +PUBLIC int st_pair_by_alloc_name_policies(st_init_info_t *info, char *cached_parent_name, char *cached_name, _magic_id_t cached_dsentry_site_id, char *local_parent_name, char *local_name, _magic_id_t local_dsentry_site_id, int num_elements, const union __alloc_flags *p_alloc_flags, int alloc_policies, int status_flags, int status_op) +{ + int r, saved_policies = st_policies; + st_policies &= ~(ST_ON_ALLOC_UNPAIR_MASK); + st_policies |= (alloc_policies & ST_ON_ALLOC_UNPAIR_MASK); + r = st_pair_by_alloc_name(info, cached_parent_name, cached_name, cached_dsentry_site_id, local_parent_name, local_name, local_dsentry_site_id, num_elements, p_alloc_flags, status_flags, status_op); + st_policies = saved_policies; + return r; +} + +PUBLIC int st_pair_by_alloc_name(st_init_info_t *info, char *cached_parent_name, char *cached_name, _magic_id_t cached_dsentry_site_id, char *local_parent_name, char *local_name, _magic_id_t local_dsentry_site_id, int num_elements, const union __alloc_flags *p_alloc_flags, int status_flags, int status_op) +{ + struct _magic_sentry *cached_sentry = NULL, *local_sentry = NULL; + struct _magic_dsindex *local_dsindex = NULL; + struct _magic_dsentry *prev_dsentry, *dsentry, *head_dsentry; + struct _magic_sentry* sentry; + int r; + int is_cached_alloc = FALSE, is_local_alloc = FALSE; + ST_CHECK_INIT(); + assert(cached_name || local_name); + assert(!((cached_name == NULL) ^ (cached_parent_name == NULL))); + assert(!((local_name == NULL) ^ (local_parent_name == NULL))); + + if (cached_name) { + EXEC_WITH_MAGIC_VARS( + cached_sentry = magic_sentry_lookup_by_name(cached_parent_name, + cached_name, cached_dsentry_site_id, NULL); + if (cached_sentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) { + is_cached_alloc = TRUE; + } + , &st_cached_magic_vars + ); + } + if (local_name) { + EXEC_WITH_MAGIC_VARS( + local_sentry = magic_sentry_lookup_by_name(local_parent_name, + local_name, local_dsentry_site_id, NULL); + if (local_sentry && MAGIC_SENTRY_IS_ALLOC(local_sentry)) { + is_local_alloc = TRUE; + } + if (!local_sentry || is_local_alloc) { + local_dsindex = magic_dsindex_lookup_by_name(local_parent_name, local_name); + if (local_dsindex && !MAGIC_DSINDEX_IS_ALLOC(local_dsindex)) { + local_dsindex = NULL; + } + if (local_sentry) assert(local_dsindex); + is_local_alloc = is_local_alloc || local_dsindex != NULL; + } + , st_local_magic_vars_ptr + ); + } + if (!is_cached_alloc && !is_local_alloc) { + if (cached_sentry || local_sentry) { + st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op); + return OK; + } + return ENOENT; + } + if (local_sentry) { + if (!is_local_alloc) { + /* Alloc sentries may have multiple instances with the same name. */ + assert(cached_sentry && is_cached_alloc); + head_dsentry = MAGIC_DSENTRY_NEXT(MAGIC_DSENTRY_FROM_SENTRY(cached_sentry)); + assert(cached_parent_name && cached_name); + MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(head_dsentry, prev_dsentry, dsentry, sentry, cached_parent_name, cached_name, cached_dsentry_site_id, + /* Cannot map multiple cached alloc sentries to a single local non-alloc sentry. */ + return E2BIG; + ); + /* Map a single cached alloc sentry to a single local non-alloc sentry. */ + st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op); + return OK; + } + else { + /* Unpair all the local alloc sentries. */ + head_dsentry = MAGIC_DSENTRY_FROM_SENTRY(local_sentry); + assert(local_parent_name && local_name); + MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(head_dsentry, prev_dsentry, dsentry, sentry, local_parent_name, local_name, local_dsentry_site_id, + st_pair_by_sentry(NULL, sentry, status_flags, status_op); + ); + } + } + if (!cached_sentry) { + return OK; + } + + /* Map a single cached non-alloc sentry to a local to-be-alloc sentry. */ + if (!is_cached_alloc) { + assert(local_dsindex); + return st_pair_alloc_by_dsindex(info, cached_sentry, local_dsindex, num_elements, p_alloc_flags, status_flags, status_op); + } + + /* Map all the cached alloc sentries to the corresponding local to-be-alloc sentries (or NULL). */ + head_dsentry = MAGIC_DSENTRY_FROM_SENTRY(cached_sentry); + assert(cached_parent_name && cached_name); + MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(head_dsentry, prev_dsentry, dsentry, + sentry, cached_parent_name, cached_name, cached_dsentry_site_id, + r = st_pair_alloc_by_dsindex(info, sentry, local_dsindex, num_elements, p_alloc_flags, status_flags, status_op); + if (r != OK) { + return r; + } + ); + + return OK; +} + +/* Metadata transfer and adjustment functions */ + +PRIVATE int transfer_metadata_functions(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, + struct _magic_vars_t *remote_magic_vars, + st_counterparts_t *counterparts) +{ + + int i; + struct _magic_function *cached_function; + + /* transfer magic_functions */ + MD_TRANSFER(info, remote_magic_vars->functions, (void **)&cached_magic_vars->functions, remote_magic_vars->functions_num * sizeof(struct _magic_function)); + + /* adjust magic_functions */ + for (i = 0 ; i < cached_magic_vars->functions_num ; i++) { + cached_function = &cached_magic_vars->functions[i]; + MD_TRANSFER_STR(info, &cached_function->name); + cached_function->type = &cached_magic_vars->types[cached_function->type - remote_magic_vars->types]; + } + + return OK; +} + +PRIVATE int transfer_metadata_dfunctions(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, + struct _magic_vars_t *remote_magic_vars, + st_counterparts_t *counterparts) +{ + + struct _magic_dfunction **dfunction_ptr; + struct _magic_dfunction *cached_dfunction, *prev_dfunction = NULL; + struct _magic_function *cached_function; + + /* Transfer dfunctions. */ + cached_magic_vars->first_dfunction = remote_magic_vars->first_dfunction; + dfunction_ptr = &cached_magic_vars->first_dfunction; + while (*dfunction_ptr != NULL) { + MD_TRANSFER(info, *dfunction_ptr, (void **)dfunction_ptr, sizeof(struct _magic_dfunction)); + cached_dfunction = *dfunction_ptr; + + /* Adjust dfunction parent_name and next/prev links. */ + if (cached_dfunction->parent_name != NULL) { + MD_TRANSFER_STR(info, &cached_dfunction->parent_name); + if (strlen(cached_dfunction->parent_name) == 0) { + printf("ERROR. strlen(dfunction->parent_name) == 0.\n"); + return EGENERIC; + } + } else { + printf("ERROR. dfunction->parent_name == NULL.\n"); + return EGENERIC; + } + + /* Adjust function name and type. */ + cached_function = &cached_dfunction->function; + MD_TRANSFER_STR(info, &cached_function->name); + cached_function->type = &cached_magic_vars->types[cached_function->type - remote_magic_vars->types]; + + if (cached_dfunction->prev != NULL) + cached_dfunction->prev = prev_dfunction; + + dfunction_ptr = &cached_dfunction->next; + prev_dfunction = cached_dfunction; + } + + cached_magic_vars->last_dfunction = prev_dfunction; + + return OK; +} + + +PUBLIC int st_transfer_metadata_types(st_init_info_t *info, struct _magic_vars_t *cached_magic_vars + , struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts) +{ + + int i; + + /* transfer types */ + MD_TRANSFER(info, remote_magic_vars->types, (void **)&cached_magic_vars->types, remote_magic_vars->types_num * sizeof(struct _magic_type)); + + /* type adjustments */ + for (i = 0 ; i < cached_magic_vars->types_num ; i++) { + if (transfer_metadata_type_members(info, &cached_magic_vars->types[i], cached_magic_vars, remote_magic_vars)) { + printf("ERROR transferring type members metadata.\n"); + return EGENERIC; + } + set_typename_key(&cached_magic_vars->types[i]); + } + + return OK; +} + +PRIVATE int transfer_metadata_type_value_set(st_init_info_t *info, struct _magic_type *type, struct _magic_vars_t *cached_magic_vars, struct _magic_vars_t *remote_magic_vars) +{ + int num_elements; + /* MD_TRANSFER cannot be used, because it will allocate space for num_elements */ + if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) type->value_set, sizeof(int), (uint32_t) &num_elements)) { + printf("ERROR transferring type value set metadata.\n"); + return EGENERIC; + } + num_elements++; + MD_TRANSFER(info, type->value_set, (void **)&type->value_set, num_elements *sizeof(int)); + return OK; +} + +PRIVATE int transfer_metadata_type_members(st_init_info_t *info, struct _magic_type *type, struct _magic_vars_t *cached_magic_vars, struct _magic_vars_t *remote_magic_vars) +{ + int r; + int num_child = MAGIC_TYPE_NUM_CONTAINED_TYPES(type), i; + + MD_TRANSFER_STR(info, &type->name); + MD_TRANSFER_STR(info, &type->type_str); + + if (type->names != NULL && type->num_names > 0) { + /* transfer array of name pointers */ + MD_TRANSFER(info, type->names, (void **)&type->names, type->num_names * sizeof(char *)); + for (i = 0 ; i < type->num_names ; i++) { + /* transfer individual name */ + MD_TRANSFER_STR(info, &type->names[i]); + } + } + + +#define MD_TRANSFER_ADJUST_MEMBER_PTR(NUM_ELEMENTS, \ + ELEMENT_SIZE,PTR_ARRAY,INDEX) \ + if((NUM_ELEMENTS) > 0 && (PTR_ARRAY) != NULL) { \ + MD_TRANSFER(info, PTR_ARRAY, (void **)&PTR_ARRAY, \ + NUM_ELEMENTS * ELEMENT_SIZE); \ + for(INDEX = 0 ; (INDEX) < (NUM_ELEMENTS) ; INDEX++) { \ + PTR_ARRAY[INDEX] = ADJUST_POINTER(cached_magic_vars->types, \ + remote_magic_vars->types, PTR_ARRAY[INDEX]); \ + } \ + } + + MD_TRANSFER_ADJUST_MEMBER_PTR( + (type->type_id == MAGIC_TYPE_FUNCTION ? num_child + 1 : num_child), + sizeof(struct _magic_type *), type->contained_types, i + ); + + if (type->compatible_types) { + struct _magic_type *comp_types_element; + int comp_types_size=0; + /* determine size of array */ + do { + if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) &type->compatible_types[comp_types_size] + , sizeof(struct _magic_type *), (uint32_t) &comp_types_element)) + { + printf("ERROR transferring compatible types array metadata.\n"); + return EGENERIC; + } + comp_types_size++; + } while(comp_types_element != NULL); + /* We know the size, now transfer the whole array */ + MD_TRANSFER(info, type->compatible_types, (void **) &type->compatible_types, comp_types_size * sizeof(struct _magic_type *)); + for (i = 0; i < comp_types_size; i++) { + if (type->compatible_types[i] != NULL) { + /* Adjust the pointer to point to the local counterpart */ + type->compatible_types[i] = ADJUST_POINTER(cached_magic_vars->types, remote_magic_vars->types, type->compatible_types[i]); + } + } + } + + if (num_child>0 && type->member_names != NULL) { + MD_TRANSFER(info, type->member_names, (void **)&type->member_names, num_child * sizeof(char *)); + for (i = 0 ; i < num_child ; i++) { + MD_TRANSFER_STR(info, &type->member_names[i]); + } + } + + if (num_child>0 && type->member_offsets != NULL) { + MD_TRANSFER(info, type->member_offsets, (void **)&type->member_offsets, num_child * sizeof(unsigned)); + } + + if (MAGIC_TYPE_HAS_VALUE_SET(type)) { + r = transfer_metadata_type_value_set(info, type, cached_magic_vars, remote_magic_vars); + if (r != OK) { + return r; + } + } + return OK; +} + +PRIVATE int transfer_metadata_sentries(st_init_info_t *info, struct _magic_vars_t *cached_magic_vars + , struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts + , int *max_buff_sz) +{ + + int i; + int skipped_sentries = 0; + struct _magic_sentry *cached_sentry; + + /* transfer sentries */ + MD_TRANSFER(info, remote_magic_vars->sentries, (void **)&cached_magic_vars->sentries, remote_magic_vars->sentries_num * sizeof(struct _magic_sentry)); + /* todo: try to use only remote_magic_vars or cached magic_vars */ + /* todo: if transfer is complete, and argument 2 and 3 are always the same, remove 2nd argument */ + + /* adjust sentries */ + for (i = 0 ; i < cached_magic_vars->sentries_num ; i++) { + cached_sentry = &cached_magic_vars->sentries[i]; + + if ((st_policies & ST_TRANSFER_DIRTY_ONLY) && + !MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DIRTY_PAGE) && + !MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_IMMUTABLE)) { + skipped_sentries++; + continue; + } + if (skipped_sentries > 0) { + cached_magic_vars->sentries[i - skipped_sentries] = + cached_magic_vars->sentries[i]; + cached_magic_vars->sentries[i - skipped_sentries].id -= + skipped_sentries; + cached_sentry = &cached_magic_vars->sentries[i - skipped_sentries]; + } + + + if (transfer_metadata_sentry_members(info, cached_sentry)) { + printf("ERROR transferring sentry members metadata.\n"); + return EGENERIC; + } + + /* + * We have to change the type to its cached counterpart, + * so that it may be compared to the local type of the local sentry counterpart. + */ + cached_sentry->type = &cached_magic_vars->types[cached_sentry->type - remote_magic_vars->types]; + + if (cached_sentry->type->size > *max_buff_sz) { + *max_buff_sz = cached_sentry->type->size; + } + } + + if (skipped_sentries > 0) + cached_magic_vars->sentries_num -= skipped_sentries; + + return OK; +} + +PRIVATE int transfer_metadata_sentry_members(st_init_info_t *info, struct _magic_sentry *sentry) +{ + if (sentry->name != NULL) { + MD_TRANSFER_STR(info, &sentry->name); + } else { + printf("ERROR. sentry->name == NULL.\n"); + return EGENERIC; + } + return OK; +} + +PUBLIC int st_transfer_metadata_dsentries(st_init_info_t *info, struct _magic_vars_t *cached_magic_vars + , struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts, int *max_buff_sz, int *dsentries_num) +{ + + struct _magic_dsentry **dsentry_ptr; +#if MAGIC_DSENTRY_ALLOW_PREV + struct _magic_dsentry *prev_dsentry = NULL; +#endif + int r; + + *dsentries_num = 0; + + cached_magic_vars->first_dsentry = remote_magic_vars->first_dsentry; + dsentry_ptr = &cached_magic_vars->first_dsentry; + while (*dsentry_ptr != NULL) { + + struct _magic_dsentry *cached_dsentry, *remote_dsentry = *dsentry_ptr; + struct _magic_sentry *sentry; + + /* transfer dsentry */ + MD_TRANSFER(info, *dsentry_ptr, (void **) dsentry_ptr, sizeof(struct _magic_dsentry)); + cached_dsentry = *dsentry_ptr; + + if ((st_policies & ST_TRANSFER_DIRTY_ONLY) && + !MAGIC_STATE_FLAG((&cached_dsentry->sentry), MAGIC_STATE_DIRTY_PAGE) && + !MAGIC_STATE_FLAG((&cached_dsentry->sentry), MAGIC_STATE_IMMUTABLE)) { + *dsentry_ptr = cached_dsentry->next; + continue; + } + + if (cached_magic_vars->first_stack_dsentry == remote_dsentry) { + cached_magic_vars->first_stack_dsentry = cached_dsentry; + } else if(cached_magic_vars->last_stack_dsentry == remote_dsentry) { + cached_magic_vars->last_stack_dsentry = cached_dsentry; + } + + /* adjust dsentry */ + if (cached_dsentry->parent_name != NULL) { + MD_TRANSFER_STR(info, &cached_dsentry->parent_name); + if (strlen(cached_dsentry->parent_name) == 0) { + printf("ERROR. strlen(dsentry->parent_name) == 0.\n"); +#if TODO_DSENTRY_PARENT_NAME_BUG + if (cached_dsentry->next != NULL) +#endif + return EGENERIC; + } + } else { + printf("ERROR. dsentry->parent_name == NULL.\n"); + return EGENERIC; + } + + sentry = &cached_dsentry->sentry; + if (transfer_metadata_sentry_members(info, sentry)) { + printf("ERROR transferring sentry members metadata.\n"); + return EGENERIC; + } + + /* Override original id to simplify pairing later. */ + sentry->id = cached_magic_vars->sentries_num + *dsentries_num + 1; + + /* + * Report violations for all the pointers pointing to the initial stack area. + * This is to make sure no assumption is incorrectly made about this area. + */ + if (!strcmp(sentry->name, MAGIC_ALLOC_INITIAL_STACK_NAME)) { + sentry->flags |= MAGIC_STATE_ADDR_NOT_TAKEN; + } + + /* + * Adjust the type, so that the local and remote type can be compared + * during a server version update + */ + if (sentry->type == &remote_dsentry->type) { + + /* + * sentry->type is contained in dsentry.type. Therefore, this is an + * array type. In order to allocate a new memory region, we only + * need the size of the type, and the contained type as arguments + * to the magic allocation function. Therefore, other members of + * the type do need to be cached or adjusted. + */ + + /* Adjust pointer to cached location */ + sentry->type = &cached_dsentry->type; + + /* Adjust contained_types to type_array located in dsentry struct. */ + sentry->type->contained_types = cached_dsentry->type_array; + + /* + * Adjust only pointer in type_array. It currently has the same + * value as the remote copy, but it has to point to the cached + * of the contained type. + */ + sentry->type->contained_types[0] = &cached_magic_vars->types[sentry->type->contained_types[0] - remote_magic_vars->types]; + + /* Adjust empty strings. */ + sentry->type->name = ""; + sentry->type->type_str = ""; + + /* Adjust value set if necessary. */ + if (MAGIC_TYPE_HAS_VALUE_SET(sentry->type)) { + r = transfer_metadata_type_value_set(info, sentry->type, cached_magic_vars, remote_magic_vars); + if (r != OK) { + return r; + } + } + } else { + + /* + * sentry.type must be in the global type array. Adjust pointer accordingly. + * The pointer is still pointing to the remote version. + * We have to change it to the cached version. + */ + sentry->type = &cached_magic_vars->types[sentry->type - remote_magic_vars->types]; + + } + + /* see if the buffer needs to be bigger for the dsentry data region. */ + if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND) && *max_buff_sz < sentry->type->size) { + *max_buff_sz = sentry->type->size; + } + + dsentry_ptr = &cached_dsentry->next; +#if MAGIC_DSENTRY_ALLOW_PREV + if (cached_dsentry->prev != NULL) + cached_dsentry->prev = prev_dsentry; + prev_dsentry = cached_dsentry; +#endif + *dsentries_num = *dsentries_num + 1; + } + + return OK; +} + +PRIVATE int pair_metadata_types(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts, int allow_unpaired_types) +{ + int i, j, num_unpaired_struct_types = 0; + int num_unpaired_types = 0; + int num_total_types = 0; + int num_struct_types = 0; + int num_unpaired_types_left, num_unpaired_struct_types_left; + + if (st_unpaired_types_ratio > 0 || st_unpaired_struct_types_ratio > 0) { + for (i = 0 ; i < cached_magic_vars->types_num ; i++) { + struct _magic_type *type = &cached_magic_vars->types[i]; + if (ST_IS_UNPAIRABLE_STRUCT_TYPE(type)) { + num_struct_types++; + } + if (ST_IS_UNPAIRABLE_TYPE(type)) { + num_total_types++; + } + } + num_unpaired_types = (int) (st_unpaired_types_ratio*num_total_types); + num_unpaired_struct_types = (int) (st_unpaired_struct_types_ratio*num_struct_types); + } + num_unpaired_types_left = num_unpaired_types; + num_unpaired_struct_types_left = num_unpaired_struct_types; + + /* type pairing, remote->local */ + for(i = 0 ; i < cached_magic_vars->types_num ; i++) { + struct _magic_type *type = &cached_magic_vars->types[i]; + counterparts->types[i].counterpart = NULL; + + if (num_unpaired_types_left > 0 && ST_IS_UNPAIRABLE_TYPE(type)) { + num_unpaired_types_left--; + continue; + } + else if (num_unpaired_struct_types_left > 0 && ST_IS_UNPAIRABLE_STRUCT_TYPE(type)) { + num_unpaired_struct_types_left--; + continue; + } + + for (j = 0 ; j < _magic_types_num ; j++) { + /* A remote type may be paired to multiple local types. + * It is safe to index only the first type since counterparts + * are only used to speed up type matching. + */ + if (magic_type_compatible(type, &_magic_types[j], MAGIC_TYPE_COMPARE_ALL)) { + counterparts->types[i].counterpart = &_magic_types[j]; + break; + } + } + + if (!allow_unpaired_types && counterparts->types[i].counterpart == NULL) { + printf("ERROR, remote type cannot be paired with a local type: "); + MAGIC_TYPE_PRINT(type, MAGIC_EXPAND_TYPE_STR); + printf("\n"); + return EGENERIC; + } + } + if (st_unpaired_types_ratio > 0 || st_unpaired_struct_types_ratio > 0) { + assert(num_unpaired_types_left == 0 && (st_unpaired_types_ratio > 0 || num_unpaired_struct_types == 0)); + _magic_printf("Unpaired types stats: unpaired types: %d, total types: %d, unpaired struct types: %d, struct types: %d\n", num_unpaired_types, num_total_types, num_unpaired_struct_types, num_struct_types); + } + + for (i = 0 ; i < cached_magic_vars->types_num ; i++) { + struct _magic_type *type = &cached_magic_vars->types[i]; + struct _magic_type *local_type = (struct _magic_type*) counterparts->types[i].counterpart; + counterparts->ptr_types[i].counterpart = NULL; + if (local_type && type->type_id == MAGIC_TYPE_POINTER) { + if (MAGIC_TYPE_HAS_COMP_TYPES(type) != MAGIC_TYPE_HAS_COMP_TYPES(local_type)) { + continue; + } + if (MAGIC_TYPE_HAS_COMP_TYPES(type)) { + j = 0; + while (MAGIC_TYPE_HAS_COMP_TYPE(type, j) && MAGIC_TYPE_HAS_COMP_TYPE(local_type, j)) { + struct _magic_type *ctype = MAGIC_TYPE_COMP_TYPE(type, j); + struct _magic_type *local_ctype = MAGIC_TYPE_COMP_TYPE(local_type, j); + if (!ST_TYPE_IS_CACHED_COUNTERPART(ctype, local_ctype)) { + break; + } + j++; + } + if (MAGIC_TYPE_HAS_COMP_TYPE(type, j) || MAGIC_TYPE_HAS_COMP_TYPE(local_type, j)) { + continue; + } + } + counterparts->ptr_types[i].counterpart = local_type; + } + } + + return OK; +} + +PRIVATE int pair_metadata_functions(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts) +{ + int i; + struct _magic_function *cached_function, *local_function; +#if ST_DEBUG_LEVEL > 0 + int num_relocated = 0; +#endif + + /* map remote functions to local functions */ + for(i = 0 ; i < cached_magic_vars->functions_num ; i++) { + cached_function = &cached_magic_vars->functions[i]; + local_function = NULL; + st_map_functions(&cached_function, &local_function); + ST_SET_CACHED_COUNTERPART(cached_function, functions, functions, local_function); + +#if CHECK_SENTITY_PAIRS + if (local_function) { + /* debug: see if the function is paired more than once */ + struct _magic_function *cfunction = NULL; + st_map_functions(&cfunction, &local_function); + if (cfunction != cached_function) { + printf("function pairing failed for (1) local function linked to multiple remote functions (2), (3)\n"); + printf("(1) "); MAGIC_FUNCTION_PRINT(local_function, 0); printf("\n"); + printf("(2) "); MAGIC_FUNCTION_PRINT(cached_function, 0); printf("\n"); + printf("(3) "); MAGIC_FUNCTION_PRINT(cfunction, 0); printf("\n"); + return EGENERIC; + } + } +#endif + +#if ST_DEBUG_LEVEL > 0 + if (local_function && cached_function->address != local_function->address) { + num_relocated++; + if (ST_DEBUG_LEVEL > 1) { + printf("- relocated function: '%s'\n", cached_magic_vars->functions[i].name); + } + } +#endif + } + +#if ST_DEBUG_LEVEL > 0 + printf("total remote functions: %d. relocated: %d\n", cached_magic_vars->functions_num, num_relocated); +#endif + + return OK; +} + +PRIVATE int pair_metadata_sentries(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts) +{ + int i, r; + struct _magic_sentry *cached_sentry, *local_sentry; +#if ST_DEBUG_LEVEL > 0 + int num_relocated_str = 0, num_relocated_normal = 0; +#endif + + /* pair sentries remote->local */ + for (i = 0 ; i < cached_magic_vars->sentries_num ; i++) { + void *local_data_addr = NULL; + cached_sentry = &cached_magic_vars->sentries[i]; + + /* String data is transferred directly. */ + if (MAGIC_SENTRY_IS_STRING(cached_sentry)) { + char *string = st_buff_allocate(info, cached_sentry->type->size); + if (!string) { + printf("ERROR allocating string.\n"); + return EGENERIC; + } + r = st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) cached_sentry->address, + cached_sentry->type->size, (uint32_t) string); + if(r != OK) { + printf("ERROR transferring string.\n"); + return EGENERIC; + } + local_data_addr = string; + } + ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries_data, local_data_addr); + + local_sentry = NULL; + st_map_sentries(&cached_sentry, &local_sentry); + ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry); + +#if CHECK_SENTITY_PAIRS + if (local_sentry && !MAGIC_SENTRY_IS_STRING(cached_sentry)) { + /* debug: see if the non-string sentry is paired more than once */ + struct _magic_sentry *csentry = NULL; + st_map_sentries(&csentry, &local_sentry); + if (csentry != cached_sentry) { + printf("sentry pairing failed for (1) local sentry linked to multiple remote sentries (2), (3)\n"); + printf("(1) "); MAGIC_SENTRY_PRINT(local_sentry, 0); printf("\n"); + printf("(2) "); MAGIC_SENTRY_PRINT(cached_sentry, 0); printf("\n"); + printf("(3) "); MAGIC_SENTRY_PRINT(csentry, 0); printf("\n"); + return EGENERIC; + } + } +#endif + +#if ST_DEBUG_LEVEL > 0 + if (local_sentry && cached_sentry->address != local_sentry->address) { + if (MAGIC_SENTRY_IS_STRING(cached_sentry)) { + num_relocated_str++; + } + else { + num_relocated_normal++; + if (ST_DEBUG_LEVEL > 1) { + printf("- relocated non-string sentry: '%s'\n", cached_sentry->name); + } + } + } +#endif + } + +#if ST_DEBUG_LEVEL > 0 + printf("total remote sentries: %d. relocated normal: %d relocated string: %d\n", cached_magic_vars->sentries_num, num_relocated_normal, num_relocated_str); +#endif + + return OK; +} + +#if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER +PRIVATE int allocate_pair_metadata_dsentries_from_raw_copy(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts) +{ + struct _magic_dsentry *dsentry; + int remote_dsentries = 0, unpaired_dsentries = 0; + +#if ST_DEBUG_LEVEL > 3 + EXEC_WITH_MAGIC_VARS( + magic_print_dsentries(); + , &st_cached_magic_vars + ); + magic_print_dsentries(); +#endif + + dsentry = cached_magic_vars->first_dsentry; + while (dsentry != NULL) { + struct _magic_sentry *local_sentry = NULL, *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry); + + /* Initialize counterpart to NULL. */ + ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, NULL); + + remote_dsentries++; + + if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_STACK) && !MAGIC_STATE_FLAG(sentry, MAGIC_STATE_LIB)) { + local_sentry = MAGIC_DSENTRY_TO_SENTRY((struct _magic_dsentry *)MAGIC_PTR_FROM_DATA(sentry->address)); + } else { +#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX + EXEC_WITH_MAGIC_VARS( + local_sentry = magic_sentry_lookup_by_range(sentry->address, NULL); + , &st_cached_magic_vars + ); +#else + local_sentry = magic_sentry_lookup_by_addr(sentry->address, NULL); +#endif + } + + if (!local_sentry) { + unpaired_dsentries++; +#if ST_DEBUG_LEVEL > 2 + printf("allocate_pair_metadata_dsentries_from_raw_copy: found unpaired "); MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR); _magic_printf("\n"); +#endif + } + ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry); + dsentry = dsentry->next; + } + +#if ST_DEBUG_LEVEL > 0 + printf("total remote dsentries: %d (%d unpaired)\n", remote_dsentries, unpaired_dsentries); +#endif + + return OK; +} + +#else + +PRIVATE int allocate_pair_metadata_dsentries(st_init_info_t *info, + struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts) +{ + struct _magic_dsentry *dsentry = cached_magic_vars->first_dsentry, *local_dsentry; + int remote_dsentries = 0; +#ifndef __MINIX + int *local_sentry_paired_by_id = st_buff_allocate(info, (_magic_sentries_next_id + 1) * sizeof(int)); +#endif + +#if ST_DEBUG_LEVEL > 3 + EXEC_WITH_MAGIC_VARS( + magic_print_dsentries(); + , &st_cached_magic_vars + ); + magic_print_dsentries(); +#endif + +#ifdef __MINIX + /* + * Since on MINIX the mmaped regions are inherited in the new process, + * we must first deallocate them. This is not the case on Linux. + */ + while (dsentry != NULL) { + int res = 0; + struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry); + int size = sentry->type->size; + /* For mmap first unmap the old region that is already mapped into this new instance */ + if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND) + && MAGIC_STATE_REGION(sentry) == MAGIC_STATE_MAP + && !USE_PRE_ALLOCATED_BUFFER(info) + ) + { + /* + * The 'ext' field in the dsentry is used here to record + * the padding for ASR. + */ + size_t padding = (size_t) dsentry->ext; + /* + * call munmap(). ptr and size have to be altered, + * in order to free the preceding page, containing the dsentry struct, too. + */ + MAGIC_MEM_WRAPPER_BLOCK( + res = munmap((char *)sentry->address - magic_get_sys_pagesize() - padding, size + magic_get_sys_pagesize() + padding); + ); + if (res != 0) { + printf("ERROR, munmap returned NULL.\n"); + return EGENERIC; + } + } + dsentry = dsentry->next; + } +#endif + + /* Permute dsentries in case of ASR. */ + if (info->flags & ST_LU_ASR) { + magic_asr_permute_dsentries(&cached_magic_vars->first_dsentry); + } + + dsentry = cached_magic_vars->first_dsentry; + while (dsentry != NULL) { + struct _magic_sentry *local_sentry, *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry); + int is_alloc_dsentry = MAGIC_SENTRY_IS_ALLOC(sentry); + int res = 0; + struct _magic_dsindex *local_dsindex; + + remote_dsentries++; + +#ifdef __MINIX + /* Cannot deal with dead dsentries. */ + assert(dsentry->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE); +#else + /* + * If there are dead dsentries, we simply skip them. + */ + if (dsentry->magic_state != MAGIC_DSENTRY_MSTATE_ALIVE) { + dsentry = dsentry->next; + continue; + } +#endif + + /* Initialize counterpart to NULL. */ + ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, NULL); + + /* Handle non-alloc dsentries first. */ + if (!is_alloc_dsentry) { + local_sentry = magic_sentry_lookup_by_name(dsentry->parent_name, + sentry->name, dsentry->site_id, NULL); + if (local_sentry) { + assert(!MAGIC_SENTRY_IS_ALLOC(local_sentry)); + ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry); + } + + dsentry = dsentry->next; + continue; + } + + /* Out-of-band alloc dsentries next. */ + if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) { + struct _magic_type *type; + /* We can only handle obdsentries with the magic void type, transferred as-is. */ + if (sentry->type != &dsentry->type) { + /* Not an array type */ + type = sentry->type; + } else { + /* This is an array type, use its contained type instead. */ + type = sentry->type->contained_types[0]; + } + /* We now have the cached version of the type. Compare it to magic void type */ + if (!magic_type_compatible(type, MAGIC_VOID_TYPE, MAGIC_TYPE_COMPARE_ALL)) { + printf("Can't handle obdsentry with non-void type\n"); + return EGENERIC; + } +#ifdef __MINIX + /* On MINIX we need to recreate all the obdsentries. */ + struct _magic_obdsentry *obdsentry; + int size = sentry->type->size; + obdsentry = magic_create_obdsentry(sentry->address, + MAGIC_VOID_TYPE, size, MAGIC_STATE_REGION(sentry), sentry->name, dsentry->parent_name); + if (obdsentry == NULL) { + printf("ERROR, magic_create_obdsentry returned NULL.\n"); + return EGENERIC; + } + local_dsentry = MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry); +#else + /* On Linux we only need to pair them. */ + local_sentry = magic_sentry_lookup_by_name( + MAGIC_SENTRY_PARENT(sentry), sentry->name, + MAGIC_SENTRY_SITE_ID(sentry), NULL); + if (local_sentry == NULL) { + printf("Unable to pair obdsentry.\n"); + return EGENERIC; + } + local_dsentry = MAGIC_DSENTRY_FROM_SENTRY(local_sentry); +#endif + ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, MAGIC_DSENTRY_TO_SENTRY(local_dsentry)); + dsentry = dsentry->next; + continue; + } + + /* Handle regular alloc dsentries last. */ +#ifndef __MINIX + /* + * For Linux, first pair INIT time remote + * dsentries with local dsentries. + */ + + if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_INIT)) { + local_sentry = NULL; + + if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_IMMUTABLE)) { + /* + * Immutable init time dsentries should have already been + * preallocated, so just pair them by address. + */ + local_sentry = magic_sentry_lookup_by_addr(sentry->address, NULL); + } else { +#if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH + struct _magic_sentry_list *local_sentry_list; + local_sentry_list = magic_sentry_list_lookup_by_name_hash( + dsentry->parent_name, sentry->name, dsentry->site_id, NULL); + + while (local_sentry_list) { + if (!local_sentry_paired_by_id[local_sentry_list->sentry->id]) { + local_sentry = local_sentry_list->sentry; + break; + } + local_sentry_list = local_sentry_list->next; + } + +#else + do { + struct _magic_dsentry *prev_dsentry, *tmp_dsentry; + struct _magic_sentry *tmp_sentry; + MAGIC_DSENTRY_LOCK(); + MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, + tmp_dsentry, tmp_sentry, + if (!strcmp(tmp_sentry->name, sentry->name)) { + if (!dsentry->parent_name || + !strcmp(MAGIC_SENTRY_PARENT(tmp_sentry), dsentry->parent_name)) { + if (dsentry->site_id == MAGIC_DSENTRY_SITE_ID_NULL || + tmp_dsentry->site_id == dsentry->site_id) { + if (!local_sentry_paired_by_id[tmp_sentry->id]) { + local_sentry = tmp_sentry; + break; + } + } + } + } + ); + MAGIC_DSENTRY_UNLOCK(); + } while (0); +#endif + } + if (local_sentry) { + ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry); + local_sentry_paired_by_id[local_sentry->id] = 1; + dsentry = dsentry->next; + continue; + } + } +#endif + + /* + * Just recreate all the other dsentries. Immutable objects will + * have already been inherited and allocate_local_dsentry() will + * not reallocate them, but instead it will just create a new + * local dsentry in the right place. + */ + local_dsindex = magic_dsindex_lookup_by_name(dsentry->parent_name, sentry->name); + if (local_dsindex || MAGIC_SENTRY_IS_LIB_ALLOC(sentry)) { + + /* Allocate a new local dsentry and pair it with the remote. */ + res = allocate_local_dsentry(info, local_dsindex, 0, 0, NULL, &local_dsentry, dsentry, NULL); + if (res != ENOSYS) { + if (res != OK) { + return res; + } + assert(local_dsentry); + ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, MAGIC_DSENTRY_TO_SENTRY(local_dsentry)); + } + } + dsentry = dsentry->next; + } + +#if ST_DEBUG_LEVEL > 0 + printf("total remote dsentries: %d\n", remote_dsentries); +#endif + + return OK; +} + +PRIVATE int deallocate_nonxferred_dsentries(struct _magic_dsentry *first_dsentry, st_counterparts_t *counterparts) +{ + struct _magic_dsentry *dsentry = first_dsentry; + struct _magic_sentry *local_sentry; + + while (dsentry != NULL) { + struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry); + int is_paired_dsentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries); + int is_alloc_dsentry = MAGIC_SENTRY_IS_ALLOC(sentry); + ST_GET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry); + + if (MAGIC_STATE_EXTF_GET(sentry, ST_TRANSFER_DONE) || !is_alloc_dsentry) { + dsentry = dsentry->next; + continue; + } + + /* Report non-transferred alloc dsentries when requested. */ + if (is_paired_dsentry && (st_policies & ST_REPORT_NONXFERRED_ALLOCS)) { + printf("deallocate_nonxferred_dsentries: Non-transferred dsentry found: "); + MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR); + printf("\n"); + } + if (!is_paired_dsentry && (st_policies & ST_REPORT_NONXFERRED_UNPAIRED_ALLOCS)) { + printf("deallocate_nonxferred_dsentries: Non-transferred unpaired dsentry found: "); + MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR); + printf("\n"); + } + + if (!is_paired_dsentry) { + dsentry = dsentry->next; + continue; + } + assert(local_sentry); + if (MAGIC_SENTRY_IS_ALLOC(local_sentry)) { + deallocate_local_dsentry(MAGIC_DSENTRY_FROM_SENTRY(local_sentry)); + } + dsentry = dsentry->next; + } + + return OK; +} +#endif + +PRIVATE void deallocate_local_dsentry(struct _magic_dsentry *local_dsentry) +{ + int r, dsentry_type; + struct _magic_sentry *local_sentry = MAGIC_DSENTRY_TO_SENTRY(local_dsentry); + + assert(MAGIC_SENTRY_IS_ALLOC(local_sentry)); + dsentry_type = MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_OUT_OF_BAND) ? MAGIC_STATE_OUT_OF_BAND : MAGIC_STATE_REGION(local_sentry); + /* A MAP_SHARED region will have both MAGIC_STATE_MAP and MAGIC_STATE_SHM. */ + if (dsentry_type == (MAGIC_STATE_MAP | MAGIC_STATE_SHM)) + dsentry_type = MAGIC_STATE_MAP; + + MAGIC_MEM_WRAPPER_BEGIN(); + switch (dsentry_type) { + case MAGIC_STATE_HEAP: + /* free */ + magic_free(local_sentry->address); + break; + + case MAGIC_STATE_MAP: + /* munmap */ + r = magic_munmap(local_sentry->address, local_sentry->type->size); + if (r != 0) { + printf("Warning: magic_munmap failed for "); + MAGIC_DSENTRY_PRINT(local_dsentry, 0); + printf("\n"); + } + break; + +#ifndef __MINIX + case MAGIC_STATE_SHM: + /* shmdt */ + r = magic_shmdt(local_sentry->address); + if (r != 0) { + printf("Warning: magic_shmdt failed for "); + MAGIC_DSENTRY_PRINT(local_dsentry, 0); + printf("\n"); + } + break; +#endif + + case MAGIC_STATE_OUT_OF_BAND: + /* out-of-band dsentry. */ + r = magic_destroy_obdsentry_by_addr(local_sentry->address); + if (r != 0) { + printf("Warning: magic_destroy_obdsentry_by_addr failed for "); + MAGIC_DSENTRY_PRINT(local_dsentry, 0); + printf("\n"); + } + break; + + default: + st_cbs_os.panic("ERROR. UNSUPPORTED DSENTRY TYPE: %d\n", dsentry_type); + } + MAGIC_MEM_WRAPPER_END(); +} + +PRIVATE int allocate_local_dsentry(st_init_info_t *info, struct _magic_dsindex *local_dsindex, int num_elements, int is_type_mismatch, const union __alloc_flags *p_alloc_flags, struct _magic_dsentry** local_dsentry_ptr, struct _magic_dsentry *cached_dsentry, void *ptr) +{ + struct _magic_dsentry *local_dsentry = NULL; + struct _magic_sentry *cached_sentry = NULL; + char *name, *parent_name; + struct _magic_type *type; + int region; + size_t size; + union __alloc_flags alloc_flags; + + /* Either a dsindex or a dsentry needs to be set. */ + assert(local_dsindex || cached_dsentry); + + if (cached_dsentry) + cached_sentry = MAGIC_DSENTRY_TO_SENTRY(cached_dsentry); + + /* name, parent_name: local_dsindex || cached_dsentry. */ + if (local_dsindex) { + assert(MAGIC_DSINDEX_IS_ALLOC(local_dsindex)); + name = local_dsindex->name; + parent_name = local_dsindex->parent_name; + } else { + assert(MAGIC_SENTRY_IS_ALLOC(cached_sentry)); + /* + * The external allocation parent_name needs to be readjusted. + * The external allocation name is adjusted after the new dsentry + * is created. + */ + name = cached_sentry->name; + if (!strcmp(cached_dsentry->parent_name, MAGIC_ALLOC_EXT_PARENT_NAME)) { + parent_name = MAGIC_ALLOC_EXT_PARENT_NAME; + } else { + int found_parent_name = 0; + struct _magic_sodesc *sodesc; + struct _magic_dsodesc *dsodesc; + MAGIC_DSODESC_LOCK(); + MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc, + if (!strcmp(cached_dsentry->parent_name, sodesc->lib.name)) { + parent_name = (char *)sodesc->lib.name; + found_parent_name = 1; + break; + } + ); + if (!found_parent_name) { + MAGIC_DSODESC_ITER(_magic_first_dsodesc, dsodesc, + if (!strcmp(cached_dsentry->parent_name, dsodesc->lib.name)) { + parent_name = (char *)dsodesc->lib.name; + found_parent_name = 1; + break; + } + ); + } + MAGIC_DSODESC_UNLOCK(); + assert(found_parent_name && "Invalid parent name for cached dsentry!"); + } + } + + /* num_elements: args || cached_sentry. */ + if (num_elements <= 0 && cached_sentry) { + num_elements = cached_sentry->type->type_id == MAGIC_TYPE_ARRAY ? + cached_sentry->type->num_child_types : 1; + } + assert(num_elements > 0); + + /* alloc_flags: args || cached_dsentry. */ + if (!p_alloc_flags) { + if (cached_dsentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) { + alloc_flags = cached_dsentry->alloc_flags; + } + } else { + alloc_flags = *p_alloc_flags; + } + + /* is_type_mismatch: args || cached_dsentry. */ + if (!is_type_mismatch && cached_dsentry) + is_type_mismatch = MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_TYPE_SIZE_MISMATCH); + + /* + * Use old address for immutable objects. + */ + /* ptr: args || cached_sentry. */ + if (!ptr && cached_sentry && + MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_IMMUTABLE)) + ptr = cached_sentry->address; + + /* region: local_dsindex || cached_sentry. */ + if (local_dsindex) + region = MAGIC_STATE_REGION(local_dsindex); + else + region = MAGIC_STATE_REGION(cached_sentry); + + /* Check if the region is ambigous. This shouldn't happen. */ + assert(!((region & (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) == + (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) && + "MAGIC_STATE_HEAP | MAGIC_STATE_MAP detected!"); +#if 0 + if ((region & (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) == + (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) { + /* Check call flags to determine what to do in the ambiguous cases. */ + region = (alloc_flags.mmap_flags && alloc_flags.mmap_prot) ? + MAGIC_STATE_MAP : MAGIC_STATE_HEAP; + } +#endif + + /* type: local_dsindex || cached_sentry. */ + if (local_dsindex) { + type = local_dsindex->type; + + if (num_elements > 1 && MAGIC_TYPE_FLAG(local_dsindex->type, MAGIC_TYPE_VARSIZE)) { + size = magic_type_alloc_get_varsized_array_size(local_dsindex->type, num_elements); + assert(size > 0); + } else { + if (is_type_mismatch) { + type = MAGIC_VOID_TYPE; + printf("WARNING: Type size mismatch dsentry detected! Ignoring dsindex type and reverting to MAGIC_TYPE_VOID.\n"); + printf("name=%s, parent_name=%s\n", local_dsindex->name, local_dsindex->parent_name); + } + size = num_elements * type->size; + } + } else { + /* + * The type will need adjusting later. + */ + type = cached_sentry->type; + size = type->size; + } + + *local_dsentry_ptr = NULL; + + if (region & MAGIC_STATE_HEAP) { + /* malloc */ + ptr = magic_malloc_positioned(type, name, parent_name, size, (ptr == NULL ? NULL : MAGIC_PTR_FROM_DATA(ptr))); + if (ptr == NULL) { + printf("ERROR, magic_malloc_positioned returned NULL.\n"); + return ENOMEM; + } + memset(ptr, 0, size); + local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr)); + } + else if (region & MAGIC_STATE_MAP) { + /* mmap */ + if (!alloc_flags.mmap_flags || !alloc_flags.mmap_prot) { + /* We need call_flags to perform mmap. */ + return ENOSYS; + } + ptr = persistent_mmap(type, name, parent_name, info, NULL, size, + alloc_flags.mmap_prot, alloc_flags.mmap_flags, -1, 0, ptr); + if (ptr == NULL) { + printf("ERROR, persistent_mmap returned NULL.\n"); + return ENOMEM; + } + if (!(alloc_flags.mmap_flags & MAP_SHARED)) + memset(ptr, 0, size); + local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr)); + } +#ifndef __MINIX + else if (region & MAGIC_STATE_SHM) { + /* shmat */ + if (!alloc_flags.shmat_flags || !alloc_flags.shmat_shmid) { + /* We need call_flags to perform shmat. */ + return ENOSYS; + } + ptr = magic_shmat(type, name, parent_name, alloc_flags.shmat_shmid, + ptr, alloc_flags.shmat_flags); + if (ptr == NULL) { + printf("ERROR, magic_shmat returned NULL.\n"); + return ENOMEM; + } + local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr)); + } +#endif + else { + if (local_dsindex) { + printf("ERROR. UNSUPPORTED DSINDEX TYPE: "); + MAGIC_DSINDEX_PRINT(local_dsindex, MAGIC_EXPAND_TYPE_STR); + } else { + printf("ERROR. UNSUPPORTED DSENTRY: "); + MAGIC_DSENTRY_PRINT(cached_dsentry, MAGIC_EXPAND_TYPE_STR); + } + printf("\n"); + return EINVAL; + } + + if (!local_dsindex) { + /* + * This was an externally allocated type and, as such, needs adjusting. + */ + assert(cached_sentry->type == &cached_dsentry->type); + local_dsentry->type = cached_dsentry->type; + if (cached_dsentry->type_array[0]->type_id == MAGIC_TYPE_POINTER) { + ST_GET_CACHED_COUNTERPART(cached_dsentry->type_array[0], types, ptr_types, local_dsentry->type_array[0]); + } else { + ST_GET_CACHED_COUNTERPART(cached_dsentry->type_array[0], types, types, local_dsentry->type_array[0]); + } + local_dsentry->sentry.type = &local_dsentry->type; + local_dsentry->sentry.type->contained_types = local_dsentry->type_array; + } + + assert(local_dsentry); + assert(local_dsentry->parent_name && strcmp(local_dsentry->parent_name, "")); + assert(local_dsentry->sentry.name && strcmp(local_dsentry->sentry.name, "")); + assert(magic_check_dsentry(local_dsentry, 0)); + *local_dsentry_ptr = local_dsentry; + + if (is_type_mismatch) + local_dsentry->sentry.flags |= MAGIC_STATE_TYPE_SIZE_MISMATCH; + + /* + * Dsentries allocated by shared libraries have the names stored in dsentry + * buffers (for now). + * Readjust the local_sentry to do this as well, since after state transfer + * cleanup the existing names will become invalid. + */ + if (!local_dsindex && MAGIC_SENTRY_IS_LIB_ALLOC(cached_sentry)) { + strncpy(local_dsentry->name_ext_buff, local_dsentry->sentry.name, + MAGIC_DSENTRY_EXT_NAME_BUFF_SIZE); + local_dsentry->sentry.name = local_dsentry->name_ext_buff; + } + + return OK; +} + +PRIVATE int check_unpaired_sentry(st_init_info_t *info, + struct _magic_sentry* cached_sentry) +{ + int sentry_needs_transfer = MAGIC_STATE_EXTF_GET(cached_sentry, ST_NEEDS_TRANSFER | ST_TRANSFER_DONE) == ST_NEEDS_TRANSFER; + int report; + + if (!sentry_needs_transfer && !MAGIC_SENTRY_IS_STRING(cached_sentry)) { + return OK; + } + + if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)) { + report = st_policies & ST_REPORT_UNPAIRED_DSENTRIES; + } + else if(MAGIC_SENTRY_IS_STRING(cached_sentry)) { + report = st_policies & ST_REPORT_UNPAIRED_STRINGS; + } + else { + report = st_policies & ST_REPORT_UNPAIRED_SENTRIES; + } + if (report) { + printf("check_unpaired_sentry: Unpaired sentry found: "); + ST_SENTRY_PRINT(cached_sentry,MAGIC_EXPAND_TYPE_STR); + printf("\n"); + } + + return OK; +} + +PUBLIC struct _magic_sentry* st_cached_to_remote_sentry(st_init_info_t *info, struct _magic_sentry *cached_sentry) +{ + struct _magic_sentry *remote_sentry; + void *local_data_addr; + ST_CHECK_INIT(); + + /* Copy metadata into metadata buffer. */ + if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)) { + magic_copy_dsentry(MAGIC_DSENTRY_FROM_SENTRY(cached_sentry), st_dsentry_buff); + remote_sentry = MAGIC_DSENTRY_TO_SENTRY(st_dsentry_buff); + } + else { + memcpy(&st_dsentry_buff->sentry, cached_sentry, sizeof(struct _magic_sentry)); + remote_sentry = &st_dsentry_buff->sentry; + } + + /* Have the remote sentry point to local data. */ + local_data_addr = NULL; + /* See if we have the data locally already first. */ + ST_GET_CACHED_COUNTERPART(cached_sentry, sentries, sentries_data, local_data_addr); + if (!local_data_addr) { + /* Copy remote data into local data buffer. */ + if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) remote_sentry->address + , remote_sentry->type->size, (uint32_t) st_data_buff)) + { + printf("ERROR transferring sentry data to local buffer.\n"); + return NULL; + } + local_data_addr = st_data_buff; + } + remote_sentry->address = local_data_addr; + + return remote_sentry; +} + +PRIVATE int transfer_data_sentry(st_init_info_t *info, + struct _magic_sentry* cached_sentry) +{ + + int r; + int st_cb_flags = ST_CB_DEFAULT_FLAGS; + struct _magic_sentry *local_sentry, *remote_sentry; + int flags = ST_SEL_ANALYZE_FLAGS; + struct st_cb_info cb_info_buff; + struct st_cb_info *cb_info = &cb_info_buff; + static _magic_selement_t magic_local_selements[MAGIC_MAX_RECURSIVE_TYPES+1]; + static int magic_flags_by_depth[MAGIC_MAX_RECURSIVE_TYPES+1]; + + /* Skip extern weak symbols. */ + if (!cached_sentry->address) { + assert(MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_EXTERNAL)); + st_set_transfer_status(ST_TRANSFER_DONE, ST_OP_ADD, cached_sentry, NULL); + return OK; + } + + /* Determine local and remote sentries from the cached version. */ + local_sentry = NULL; + st_lookup_sentry_pair(&cached_sentry, &local_sentry); + assert(local_sentry && "Unexpected unpaired sentry!"); + remote_sentry = st_cached_to_remote_sentry(info, cached_sentry); + if (!remote_sentry) { + printf("No remote sentry found for cached sentry: "); + MAGIC_SENTRY_PRINT(cached_sentry, 0); + printf("\n"); + return EFAULT; + } + + cb_info->local_selements = magic_local_selements; + cb_info->local_selement = magic_selement_from_sentry(local_sentry, &magic_local_selements[0]); + cb_info->walk_flags = MAGIC_TYPE_WALK_DEFAULT_FLAGS; + cb_info->st_cb_flags = st_cb_flags; + cb_info->init_info = info; + cb_info->st_cb_saved_flags = magic_flags_by_depth; + magic_flags_by_depth[0] = st_cb_flags; + + EXEC_WITH_MAGIC_VARS( + r = magic_sentry_analyze(remote_sentry , flags, transfer_data_selement, cb_info, NULL); + , &st_cached_magic_vars + ); + if (r < 0) { + return r; + } + + st_set_transfer_status(ST_TRANSFER_DONE, ST_OP_ADD, cached_sentry, NULL); + return OK; +} + +PRIVATE int transfer_data_selement(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, void *cb_args) +{ + + int r = ST_CB_NOT_PROCESSED; + int depth, cb_flags; + struct st_cb_info *cb_info = (struct st_cb_info *) cb_args; + _magic_selement_t *local_selement, *local_parent_selement; + st_cb_selement_transfer_t *cb; + + register_typenames_and_callbacks(); + + if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) { + depth = selement->depth; + local_selement = &cb_info->local_selements[depth]; + if (depth > 0) { + local_parent_selement = &cb_info->local_selements[depth-1]; + local_selement->sentry = local_parent_selement->sentry; + local_selement->parent_type = local_parent_selement->type; + local_selement->parent_address = local_parent_selement->address; + cb_info->st_cb_flags = cb_info->st_cb_saved_flags[depth-1]; + } + /* Map the cached and the local selement. */ + st_map_selement(selement, local_selement, cb_info, FALSE); + if (local_selement->type == NULL) { + /* Unpaired selement. */ + if (st_policies & ST_REPORT_UNPAIRED_SELEMENTS) { + printf("transfer_data_selement: Unpaired selement found: "); + MAGIC_SELEMENT_PRINT(selement, MAGIC_EXPAND_TYPE_STR); + printf("\n"); + } + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + } + cb_info->local_selement = local_selement; + + /* See if identity transfer has been requested. */ + if (cb_info->st_cb_flags & ST_CB_FORCE_IXFER) { + r = transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + assert(r != ST_CB_NOT_PROCESSED); + cb_info->st_cb_saved_flags[depth] = cb_info->st_cb_flags; + return r; + } + } + + cb_flags = ST_CB_TYPE_SELEMENT; + if (ST_TYPE_NAME_KEY(selement->type) != NULL) { + cb_flags |= ST_CB_TYPE_TYPENAME; + } + if (selement->num == 1) { + cb_flags |= ST_CB_TYPE_SENTRY; + } + + cb = st_cbs.st_cb_selement_transfer[cb_flags]; + while (TRUE) { + + if (*cb != NULL) { + r = (*cb)(selement, sel_analyzed, sel_stats, cb_info); + } else { + r = default_transfer_selement_sel_cb(selement, sel_analyzed, sel_stats, cb_info); + assert(r != ST_CB_NOT_PROCESSED + && "Default selement callback should always process the selement."); + } + + if (r != ST_CB_NOT_PROCESSED) { + assert((r<0 || MAGIC_SENTRY_ANALYZE_IS_VALID_RET(r)) && "Invalid callback return code!"); + if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) { + cb_info->st_cb_saved_flags[depth] = cb_info->st_cb_flags; + } + return r; + } + + cb++; + } + + /* Not reachable. */ + return EINTR; +} + +PRIVATE int lookup_trg_info(_magic_selement_t *selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info, + _magic_selement_t *cached_trg_selement, _magic_selement_t *local_trg_selement) +{ + _magic_selement_t *local_selement, *trg_selement; + struct _magic_sentry *cached_trg_sentry, *local_trg_sentry = NULL; + struct _magic_function *cached_trg_function, *local_trg_function = NULL; + _magic_sel_analyzed_t local_sel_analyzed; + _magic_sel_stats_t local_sel_stats; + void *local_trg_root_address; + struct _magic_type *cached_trg_root_type, *local_trg_root_type; + int first_legal_trg_type, is_same_type, is_same_trg_type, local_trg_has_addr_not_taken; + + local_selement = cb_info->local_selement; + first_legal_trg_type = sel_analyzed->u.ptr.first_legal_trg_type; + assert(first_legal_trg_type >= 0); + trg_selement = &sel_analyzed->u.ptr.trg_selements[first_legal_trg_type]; + local_trg_root_type = NULL; + + /* Lookup cached and local targets. */ + if (MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(sel_analyzed)) { + cached_trg_sentry = trg_selement->sentry; + local_trg_sentry = NULL; + st_lookup_sentry_pair(&cached_trg_sentry, &local_trg_sentry); + *cached_trg_selement = *trg_selement; + cached_trg_root_type = cached_trg_sentry->type; + local_trg_has_addr_not_taken = local_trg_sentry && MAGIC_STATE_FLAG(local_trg_sentry, MAGIC_STATE_ADDR_NOT_TAKEN); + local_trg_selement->sentry = local_trg_sentry; + if (local_trg_sentry) { + local_trg_root_address = local_trg_sentry->address; + local_trg_root_type = local_trg_sentry->type; + } + } + else if(MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(sel_analyzed)) { + cached_trg_function = MAGIC_DFUNCTION_TO_FUNCTION(&sel_analyzed->u.ptr.trg.dfunction); + local_trg_function = NULL; + st_lookup_function_pair(&cached_trg_function, &local_trg_function); + *cached_trg_selement = *trg_selement; + cached_trg_root_type = cached_trg_function->type; + local_trg_has_addr_not_taken = local_trg_function && MAGIC_STATE_FLAG(local_trg_function, MAGIC_STATE_ADDR_NOT_TAKEN); + local_trg_selement->sentry = NULL; + if (local_trg_function) { + local_trg_root_address = local_trg_function->address; + local_trg_root_type = local_trg_function->type; + } + } + + /* Check unpaired targets. */ + if (!local_trg_root_type) { + local_trg_selement->type = NULL; + return OK; + } + + /* Check address not taken violations. */ + if (local_trg_has_addr_not_taken) { + ST_CB_PRINT(ST_CB_ERR, "uncaught ptr with paired target whose address is not taken", selement, sel_analyzed, sel_stats, cb_info); + return EFAULT; + } + + /* Check types and return immediately in case of perfect pointer match. */ + is_same_type = selement->type == local_selement->type || ST_PTR_TYPE_IS_CACHED_COUNTERPART(selement->type, local_selement->type); + is_same_trg_type = ST_TYPE_IS_CACHED_COUNTERPART(cached_trg_root_type, local_trg_root_type); + if (is_same_type && is_same_trg_type) { + local_trg_selement->type = cached_trg_selement->type; + local_trg_selement->address = (char*) local_trg_root_address + sel_analyzed->u.ptr.trg_offset; + return OK; + } +#if CHECK_ASR && !FORCE_SOME_UNPAIRED_TYPES + if (cb_info->init_info->flags & ST_LU_ASR) { + st_cbs_os.panic("ASR should never get here!"); + } +#endif + + /* Map sel_analyzed to its local counterpart. */ + if (is_same_trg_type) { + local_sel_analyzed = *sel_analyzed; + local_sel_analyzed.u.ptr.trg_selements[0].address = (char*) local_trg_root_address + sel_analyzed->u.ptr.trg_offset; + } + else { + st_map_sel_analyzed_from_target(sel_analyzed, &local_sel_analyzed, local_trg_sentry, local_trg_function, cb_info); + if (local_sel_analyzed.u.ptr.num_trg_types == 0) { + /* Unpaired target selements. */ + local_trg_selement->type = NULL; + return OK; + } + } + + /* Check violations on the local target. */ + memset(&local_sel_stats, 0, sizeof(local_sel_stats)); + magic_selement_analyze_ptr_type_invs(local_selement, &local_sel_analyzed, &local_sel_stats); + if (MAGIC_SEL_STATS_HAS_VIOLATIONS(&local_sel_stats)) { + /* Local pointer with violations found */ + ST_CB_PRINT(ST_CB_ERR, "uncaught ptr with after-transfer violations", selement, sel_analyzed, sel_stats, cb_info); + ST_CB_PRINT(ST_CB_ERR, "transferred ptr with violations", local_selement, &local_sel_analyzed, &local_sel_stats, cb_info); + return EFAULT; + } + + /* All the targets mapped correctly. */ + local_trg_selement->type = local_sel_analyzed.u.ptr.trg_selements[0].type; + local_trg_selement->address = local_sel_analyzed.u.ptr.trg_selements[0].address; + return OK; +} + +/* transfer helper functions */ + +PRIVATE int md_transfer_str(st_init_info_t *info, char **str_pt) +{ + char buff[ST_STR_BUFF_SIZE + 2]; + + if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) *str_pt, ST_STR_BUFF_SIZE + 1, (uint32_t) buff)) { + st_cbs_os.panic("md_transfer_str(): ERROR transferring string.\n"); + return EGENERIC; + } + buff[ST_STR_BUFF_SIZE + 1] = '\0'; + if (strlen(buff) > ST_STR_BUFF_SIZE) { + st_cbs_os.panic("md_transfer_str(): transferred string has a wrong size: %d\n", strlen(buff)); + return EGENERIC; + } + + *str_pt = st_buff_allocate(info, strlen(buff) + 1); + if (!*str_pt) { + st_cbs_os.panic("md_transfer_str(): string buffer could not be allocated.\n"); + return EGENERIC; + } + strcpy(*str_pt, buff); + return OK; +} + +PRIVATE int md_transfer(st_init_info_t *info, void *from, void **to, int len) +{ + /* backup from value, in case &from == to */ + void *from_backup = from; + *to = st_buff_allocate(info, len); + if (!*to) { + st_cbs_os.panic("md_transfer(): buffer could not be allocated.\n"); + return EGENERIC; + } + if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) from_backup, len, (uint32_t) *to)) { + st_cbs_os.panic("md_transfer(): ERROR transferring remote data to buffer.\n"); + return EGENERIC; + } + return OK; +} + + +/* Buffer allocation */ + +PRIVATE void *persistent_mmap(__MA_ARGS__ st_init_info_t *info, void *start, size_t length, int prot, int flags, int fd, off_t offset, struct _magic_dsentry *dsentry) { + if (USE_PRE_ALLOCATED_BUFFER(info)) { + size_t alloc_length = length + (length % magic_get_sys_pagesize() == 0 ? 0 : magic_get_sys_pagesize() - (length % magic_get_sys_pagesize())); + char *ptr, *data_ptr; + + assert(((char *)info->init_buff_cleanup_start) + alloc_length + magic_get_sys_pagesize() <= st_pre_allocated_page_pt && "mmap region hits temporary buffer."); + assert(((char *)info->init_buff_cleanup_start) + alloc_length + magic_get_sys_pagesize() <= ((char *) info->init_buff_start) + info->init_buff_len && "mmap region hits end of pre-allocated buffer"); + + ptr = ((char *)info->init_buff_cleanup_start) + magic_get_sys_pagesize() - MAGIC_SIZE_TO_REAL(0); + data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, (int) MAGIC_STATE_MAP); + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = flags; + MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = prot; + info->init_buff_cleanup_start = &data_ptr[alloc_length]; + return data_ptr; + } else { + /* no pre-allocated mmap buffer. Call magic_mmap to allocate region. */ + return magic_mmap_positioned(type, name, parent_name + , NULL, length, prot, flags, -1, 0, dsentry); + } +} + +PUBLIC void *st_cb_pages_allocate(st_init_info_t *info, uint32_t *phys, int num_pages) +{ + void *result; + int len = num_pages * magic_get_sys_pagesize(); + + if (USE_PRE_ALLOCATED_BUFFER(info)) { + if (!st_pre_allocated_page_pt) { +#if ST_DEBUG_LEVEL > 0 + printf("st_pages_allocate: initializing pre-allocated page buffer.\n"); +#endif + st_pre_allocated_page_pt = &((char *)info->init_buff_start)[info->init_buff_len]; + } + st_pre_allocated_page_pt -= len; + assert(st_pre_allocated_page_pt >= (char *)info->init_buff_cleanup_start + && "Temporary buffer ran into perminently pre-allocated mmapped pages."); + return st_pre_allocated_page_pt; + } + + result = st_cbs_os.alloc_contig(len, 0, NULL); + if (result == NULL) { + printf("st_pages_allocate: alloc_contig(%d) failed.\n", len); + return NULL; + } + + *phys = (uint32_t) NULL; /* we don't know or need the physical address in order to free */ + + return result; +} + +PUBLIC void st_cb_pages_free(st_init_info_t *info, st_alloc_pages *current_page) +{ + st_alloc_pages *to_be_freed; + int result; + + if (USE_PRE_ALLOCATED_BUFFER(info)) { + /* nothing to do */ + return; + } + + while (current_page != NULL) { + to_be_freed = current_page; + current_page = current_page->previous; + + result = st_cbs_os.free_contig(to_be_freed->virt_addr, to_be_freed->num_pages * magic_get_sys_pagesize()); + + if (result != OK) { + printf("munmap result != ok, using free()\n"); + /* + * NOTE: in case this is moved out of a magic_* module it needs to be + * manually annotated so it doesn't get instrumented. + */ + free(to_be_freed->virt_addr); + } + + } + +} + +PUBLIC void *st_buff_allocate(st_init_info_t *info, size_t size) +{ + void *result; + + if (size > st_alloc_buff_available) { + + int pagesize = magic_get_sys_pagesize(); + uint32_t phys; + st_alloc_pages *buff_previous_page = st_alloc_pages_current; + + /* calculate number of pages needed */ + int pages_needed = (size + sizeof(st_alloc_pages)) / pagesize; + if ((size + sizeof(st_alloc_pages)) % pagesize) + pages_needed++; + + /* allocate pages */ + st_alloc_pages_current + = st_cbs.st_cb_pages_allocate(info, &phys, pages_needed); + + if (!st_alloc_pages_current) { + printf("Could not allocate buffer.\n"); + return NULL; + } + + /* set allocation struct */ + st_alloc_pages_current->virt_addr = st_alloc_pages_current; + st_alloc_pages_current->phys_addr = phys; + st_alloc_pages_current->num_pages = pages_needed; + st_alloc_pages_current->previous = buff_previous_page; + + /* requested space is right after the struct */ + st_alloc_buff_pt = (char *) st_alloc_pages_current; + st_alloc_buff_pt += sizeof(st_alloc_pages); + /* subtract the struct size from the available buffer */ + st_alloc_buff_available = pages_needed * pagesize - sizeof(st_alloc_pages); + + } + + /* return current buffer pointer */ + result = st_alloc_buff_pt; + /* set buffer pointer after space that is requested, ready for next allocation */ + st_alloc_buff_pt += size; + /* adjust available space */ + st_alloc_buff_available -= size; + + return result; + +} + +PUBLIC void st_buff_cleanup(st_init_info_t *info) +{ + st_cbs.st_cb_pages_free(info, st_alloc_pages_current); + st_alloc_pages_current = NULL; + st_alloc_buff_available = 0; + st_alloc_buff_pt = NULL; +} + +PUBLIC void st_cleanup(st_init_info_t *info) +{ + +#if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX + st_cleanup_rl_index(info, &st_cached_magic_vars); + st_cleanup_rl_index(info, _magic_vars); +#endif + +#if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH + st_cleanup_sentry_hash(info, &st_cached_magic_vars); + st_cleanup_sentry_hash(info, _magic_vars); +#endif + +#if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH + st_cleanup_function_hash(info, &st_cached_magic_vars); + st_cleanup_function_hash(info, _magic_vars); +#endif + +#if !ST_ASSUME_RAW_COPY_BEFORE_TRANSFER + assert( + deallocate_nonxferred_dsentries(st_cached_magic_vars.first_dsentry, + &st_counterparts) == OK && + "ERROR occurred during call to deallocate_nonxferred_dsentries()."); +#endif + + /* + * Free all temporary allocated memory. + */ + st_buff_cleanup(info); + + /* + * Reset all values in case of successive state transfers. + */ + st_init_done = FALSE; + st_pre_allocated_page_pt = NULL; + st_dsentry_buff = NULL; + st_data_buff = NULL; + st_num_type_transformations = 0; + st_local_magic_vars_ptr = &_magic_vars_buff; + st_policies = ST_POLICIES_DEFAULT; + st_unpaired_types_ratio = ST_UNPAIRED_TYPES_RATIO_DEFAULT; + st_unpaired_struct_types_ratio = ST_UNPAIRED_STRUCT_TYPES_RATIO_DEFAULT; + + /* Reallow mempool dsentries lookups. */ + magic_lookup_nested_dsentries = 1; +} + +/* State cleanup/checking functions. */ + +/*===========================================================================* + * do_st_before_receive * + *===========================================================================*/ +PUBLIC void do_st_before_receive() +{ +/* Handle State transfer before receive events. */ + int num_violations; + + assert(st_state_checking_before_receive_is_enabled()); + + num_violations = st_do_state_checking(); + if (__st_before_receive_sc_max_cycles < LONG_MAX) { + __st_before_receive_sc_max_cycles--; + } + if (__st_before_receive_sc_max_violations < LONG_MAX) { + __st_before_receive_sc_max_violations -= num_violations; + } + if (__st_before_receive_sc_max_cycles <= 0) { + st_state_checking_before_receive_set_enabled(0, 0, 0); + printf("Maximum number of cycles reached\n"); + } + if (__st_before_receive_sc_max_violations <= 0) { + st_state_checking_before_receive_set_enabled(0, 0, 0); + printf("Maximum number of violations reached\n"); + } +} + +/*===========================================================================* + * st_state_checking_before_receive_is_enabled * + *===========================================================================*/ +PUBLIC int st_state_checking_before_receive_is_enabled() +{ + return __st_before_receive_enabled; +} + +/*===========================================================================* + * st_state_checking_before_receive_set_enabled * + *===========================================================================*/ +PUBLIC int st_state_checking_before_receive_set_enabled(int enabled, + int max_cycles, int max_violations) +{ + int was_enabled = __st_before_receive_enabled; + __st_before_receive_enabled = enabled; + if (enabled) { + if (max_cycles <= 0) { + max_cycles = ST_STATE_CHECKING_DEFAULT_MAX_CYCLES; + } + if (max_violations <= 0) { + max_violations = ST_STATE_CHECKING_DEFAULT_MAX_VIOLATIONS; + } + __st_before_receive_sc_max_cycles = max_cycles; + __st_before_receive_sc_max_violations = max_violations; + printf("Continuous state checking enabled, max cycles=%d, max violations=%d\n", + max_cycles == LONG_MAX ? 0 : max_cycles, + max_violations == LONG_MAX ? 0 : max_violations); + } + else { + printf("Continuous state checking disabled\n"); + } + return was_enabled; +} + +/*===========================================================================* + * st_cb_state_checking_wrapper * + *===========================================================================*/ +PRIVATE int st_cb_state_checking_wrapper(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args) +{ + struct st_cb_info cb_info_buff; + struct st_cb_info *cb_info = &cb_info_buff; + int *num_violations = (int*) cb_args; + int ret; + + cb_info->local_selements = NULL; + cb_info->local_selement = NULL; + cb_info->walk_flags = MAGIC_TYPE_WALK_DEFAULT_FLAGS; + cb_info->st_cb_flags = ST_CB_CHECK_ONLY; + cb_info->st_cb_saved_flags = NULL; + cb_info->init_info = NULL; + + ret = transfer_data_selement(selement, sel_analyzed, sel_stats, cb_info); + if (ret < 0) { + ret = st_cbs.st_cb_state_checking(selement, sel_analyzed, sel_stats, cb_args); + (*num_violations)++; + } + return ret; +} + +/*===========================================================================* + * st_do_state_checking * + *===========================================================================*/ +PUBLIC int st_do_state_checking() +{ + int num_violations = 0; + magic_sentries_analyze(ST_SEL_ANALYZE_FLAGS, + st_cb_state_checking_wrapper, &num_violations, NULL); + return num_violations; +} + +/*===========================================================================* + * st_cb_state_checking_null * + *===========================================================================*/ +PUBLIC int st_cb_state_checking_null(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args) +{ + return EINTR; +} + +/*===========================================================================* + * st_cb_state_checking_print * + *===========================================================================*/ +PUBLIC int st_cb_state_checking_print(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args) +{ + printf("%s. Found state violation:\n", st_cbs_os.debug_header()); + magic_sentry_print_el_cb(selement, sel_analyzed, sel_stats, cb_args); + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; +} + +/*===========================================================================* + * st_cb_state_checking_panic * + *===========================================================================*/ +PUBLIC int st_cb_state_checking_panic(_magic_selement_t* selement, + _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, + void* cb_args) +{ + st_cb_state_checking_print(selement, sel_analyzed, sel_stats, cb_args); + st_cbs_os.panic("Time to panic..."); + return MAGIC_SENTRY_ANALYZE_STOP; +} + +/*===========================================================================* + * st_do_state_cleanup * + *===========================================================================*/ +PUBLIC int st_do_state_cleanup() +{ + return st_cbs.st_cb_state_cleanup(); +} + +/*===========================================================================* + * st_cb_state_cleanup_null * + *===========================================================================*/ +PUBLIC int st_cb_state_cleanup_null() { + return OK; +} + +#ifndef __MINIX +/*===========================================================================* + * st_msync_all_shm_dsentries * + *===========================================================================*/ +PUBLIC void st_msync_all_shm_dsentries(void) { + struct _magic_dsentry *prev_dsentry, *dsentry; + struct _magic_sentry *sentry; + MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, + dsentry, sentry, + + /* + * TODO: + * - Don't msync mmaps of /dev/zero + */ + if (MAGIC_STATE_FLAGS(sentry, MAGIC_STATE_SHM | MAGIC_STATE_MAP) && + !(dsentry->alloc_mmap_flags & MAP_ANONYMOUS)) + msync(MAGIC_PTR_TO_DATA(dsentry), sentry->type->size, + MS_SYNC | MS_INVALIDATE); + + ); +} +#endif + diff --git a/minix/llvm/static/magic/minix/magic_ds.c b/minix/llvm/static/magic/minix/magic_ds.c new file mode 100644 index 000000000..12cfe5b54 --- /dev/null +++ b/minix/llvm/static/magic/minix/magic_ds.c @@ -0,0 +1,82 @@ +#include +#include +#include + +#include +#include +#include "ds/store.h" + +#include +#include + +char* sef_sf_typename_keys[] = { "dsi_u", NULL }; +#define dsi_u_idx 0 + +/*===========================================================================* + * sef_cb_sf_transfer_dsi_u * + *===========================================================================*/ +static int sef_cb_sf_transfer_dsi_u(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) { + static struct dsi_mem noxfer_dsi_mem_stub; + static const struct _magic_type* _magic_dsi_mem_type = NULL; + struct data_store* dsp; + _magic_selement_t parent_selement; + int ret = EGENERIC; + VOLATILE int keep_stubs = (int)&noxfer_dsi_mem_stub; + assert(keep_stubs); + + if(magic_selement_get_parent(selement, &parent_selement) == NULL) { + ST_CB_PRINT(ST_CB_ERR, "sef_cb_sf_transfer_dsi_u: magic_selement_get_parent failed", selement, sel_analyzed, sel_stats, cb_info); + return EINVAL; + } + dsp = (struct data_store*) parent_selement.address; + if(!(dsp->flags & DSF_IN_USE)) { + /* Skip when unused. */ + return MAGIC_SENTRY_ANALYZE_SKIP_PATH; + } + switch(dsp->flags & DSF_MASK_TYPE) { + case DSF_TYPE_U32: + case DSF_TYPE_LABEL: + /* Identity transfer when no ptr is involved. */ + ret = st_cb_transfer_identity(selement, sel_analyzed, sel_stats, cb_info); + break; + case DSF_TYPE_STR: + case DSF_TYPE_MEM: + /* Transfer as dsp->u.mem struct. */ + if(!_magic_dsi_mem_type && !(_magic_dsi_mem_type = magic_type_lookup_by_name("dsi_mem"))) { + ST_CB_PRINT(ST_CB_ERR, "sef_cb_sf_transfer_dsi_u: type dsi_mem not found", selement, sel_analyzed, sel_stats, cb_info); + return ENOENT; + } + st_cb_selement_type_cast(_magic_dsi_mem_type, _magic_dsi_mem_type, selement, sel_analyzed, sel_stats, cb_info); + ret = st_cb_transfer_selement_generic(selement, sel_analyzed, sel_stats, cb_info); + break; + default: + /* Unknown? Report error. */ + ST_CB_PRINT(ST_CB_ERR, "sef_cb_sf_transfer_dsi_u: bad flags", selement, sel_analyzed, sel_stats, cb_info); + ret = EFAULT; + break; + } + return ret; +} + +/*===========================================================================* + * sef_cb_sf_transfer_typename * + *===========================================================================*/ +int sef_cb_sf_transfer_typename(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info) { + const char *typename_key = ST_TYPE_NAME_KEY(selement->type); + if(ST_TYPE_NAME_MATCH(sef_sf_typename_keys[dsi_u_idx],typename_key)) + { + return sef_cb_sf_transfer_dsi_u(selement, sel_analyzed, sel_stats, cb_info); + } + + return ST_CB_NOT_PROCESSED; +} + +/*===========================================================================* + * _magic_ds_st_init * + *===========================================================================*/ +void _magic_ds_st_init(void) +{ + st_register_typename_keys(sef_sf_typename_keys); + st_setcb_selement_transfer(sef_cb_sf_transfer_typename, ST_CB_TYPE_TYPENAME); +} + diff --git a/minix/llvm/static/magic/minix/magic_util.c b/minix/llvm/static/magic/minix/magic_util.c new file mode 100644 index 000000000..0950d9465 --- /dev/null +++ b/minix/llvm/static/magic/minix/magic_util.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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); +}