blob: 839e54621442f189919bd854394a51f628909c7e [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- Representation of source level types. tytypes.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2008-2015 OpenWorks LLP
info@open-works.co.uk
This program 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 of the
License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
Neither the names of the U.S. Department of Energy nor the
University of California nor the names of its contributors may be
used to endorse or promote products derived from this software
without prior written permission.
*/
#include "pub_core_basics.h"
#include "pub_core_debuginfo.h"
#include "pub_core_libcassert.h"
#include "pub_core_libcbase.h"
#include "pub_core_libcprint.h"
#include "pub_core_xarray.h" /* to keep priv_tytypes.h happy */
#include "priv_misc.h" /* dinfo_zalloc/free/strdup */
#include "priv_d3basics.h" /* ML_(evaluate_Dwarf3_Expr) et al */
#include "priv_tytypes.h" /* self */
/* Does this TyEnt denote a type, as opposed to some other kind of
thing? */
Bool ML_(TyEnt__is_type)( const TyEnt* te )
{
switch (te->tag) {
case Te_EMPTY: case Te_INDIR: case Te_UNKNOWN:
case Te_Atom: case Te_Field: case Te_Bound:
return False;
case Te_TyBase: case Te_TyPtr: case Te_TyRef:
case Te_TyPtrMbr: case Te_TyRvalRef: case Te_TyTyDef:
case Te_TyStOrUn: case Te_TyEnum: case Te_TyArray:
case Te_TyFn: case Te_TyQual: case Te_TyVoid:
return True;
default:
vg_assert(0);
}
}
/* Print a TyEnt, debug-style. */
static void pp_XArray_of_cuOffs ( const XArray* xa )
{
Word i;
VG_(printf)("{");
for (i = 0; i < VG_(sizeXA)(xa); i++) {
UWord cuOff = *(UWord*)VG_(indexXA)(xa, i);
VG_(printf)("0x%05lx", cuOff);
if (i+1 < VG_(sizeXA)(xa))
VG_(printf)(",");
}
VG_(printf)("}");
}
void ML_(pp_TyEnt)( const TyEnt* te )
{
VG_(printf)("0x%05lx ", te->cuOff);
switch (te->tag) {
case Te_EMPTY:
VG_(printf)("EMPTY");
break;
case Te_INDIR:
VG_(printf)("INDIR(0x%05lx)", te->Te.INDIR.indR);
break;
case Te_UNKNOWN:
VG_(printf)("UNKNOWN");
break;
case Te_Atom:
VG_(printf)("Te_Atom(%s%lld,\"%s\")",
te->Te.Atom.valueKnown ? "" : "unknown:",
te->Te.Atom.value, te->Te.Atom.name);
break;
case Te_Field:
if (te->Te.Field.nLoc == -1)
VG_(printf)("Te_Field(ty=0x%05lx,pos.offset=%ld,\"%s\")",
te->Te.Field.typeR, te->Te.Field.pos.offset,
te->Te.Field.name ? te->Te.Field.name : "");
else
VG_(printf)("Te_Field(ty=0x%05lx,nLoc=%ld,pos.loc=%p,\"%s\")",
te->Te.Field.typeR, te->Te.Field.nLoc,
te->Te.Field.pos.loc,
te->Te.Field.name ? te->Te.Field.name : "");
break;
case Te_Bound:
VG_(printf)("Te_Bound[");
if (te->Te.Bound.knownL)
VG_(printf)("%lld", te->Te.Bound.boundL);
else
VG_(printf)("??");
VG_(printf)(",");
if (te->Te.Bound.knownU)
VG_(printf)("%lld", te->Te.Bound.boundU);
else
VG_(printf)("??");
VG_(printf)("]");
break;
case Te_TyBase:
VG_(printf)("Te_TyBase(%d,%c,\"%s\")",
te->Te.TyBase.szB, te->Te.TyBase.enc,
te->Te.TyBase.name ? te->Te.TyBase.name
: "(null)" );
break;
case Te_TyPtr:
VG_(printf)("Te_TyPtr(%d,0x%05lx)", te->Te.TyPorR.szB,
te->Te.TyPorR.typeR);
break;
case Te_TyRef:
VG_(printf)("Te_TyRef(%d,0x%05lx)", te->Te.TyPorR.szB,
te->Te.TyPorR.typeR);
break;
case Te_TyPtrMbr:
VG_(printf)("Te_TyMbr(%d,0x%05lx)", te->Te.TyPorR.szB,
te->Te.TyPorR.typeR);
break;
case Te_TyRvalRef:
VG_(printf)("Te_TyRvalRef(%d,0x%05lx)", te->Te.TyPorR.szB,
te->Te.TyPorR.typeR);
break;
case Te_TyTyDef:
VG_(printf)("Te_TyTyDef(0x%05lx,\"%s\")",
te->Te.TyTyDef.typeR,
te->Te.TyTyDef.name ? te->Te.TyTyDef.name
: "" );
break;
case Te_TyStOrUn:
if (te->Te.TyStOrUn.complete) {
VG_(printf)("Te_TyStOrUn(%lu,%c,%p,\"%s\")",
te->Te.TyStOrUn.szB,
te->Te.TyStOrUn.isStruct ? 'S' : 'U',
te->Te.TyStOrUn.fieldRs,
te->Te.TyStOrUn.name ? te->Te.TyStOrUn.name
: "" );
pp_XArray_of_cuOffs( te->Te.TyStOrUn.fieldRs );
} else {
VG_(printf)("Te_TyStOrUn(INCOMPLETE,\"%s\")",
te->Te.TyStOrUn.name);
}
break;
case Te_TyEnum:
VG_(printf)("Te_TyEnum(%d,%p,\"%s\")",
te->Te.TyEnum.szB, te->Te.TyEnum.atomRs,
te->Te.TyEnum.name ? te->Te.TyEnum.name
: "" );
if (te->Te.TyEnum.atomRs)
pp_XArray_of_cuOffs( te->Te.TyEnum.atomRs );
break;
case Te_TyArray:
VG_(printf)("Te_TyArray(0x%05lx,%p)",
te->Te.TyArray.typeR, te->Te.TyArray.boundRs);
if (te->Te.TyArray.boundRs)
pp_XArray_of_cuOffs( te->Te.TyArray.boundRs );
break;
case Te_TyFn:
VG_(printf)("Te_TyFn");
break;
case Te_TyQual:
VG_(printf)("Te_TyQual(%c,0x%05lx)", te->Te.TyQual.qual,
te->Te.TyQual.typeR);
break;
case Te_TyVoid:
VG_(printf)("Te_TyVoid%s",
te->Te.TyVoid.isFake ? "(fake)" : "");
break;
default:
vg_assert(0);
}
}
/* Print a whole XArray of TyEnts, debug-style */
void ML_(pp_TyEnts)( const XArray* tyents, const HChar* who )
{
Word i, n;
VG_(printf)("------ %s ------\n", who);
n = VG_(sizeXA)( tyents );
for (i = 0; i < n; i++) {
const TyEnt* tyent = VG_(indexXA)( tyents, i );
VG_(printf)(" [%5ld] ", i);
ML_(pp_TyEnt)( tyent );
VG_(printf)("\n");
}
}
/* Print a TyEnt, C style, chasing stuff as necessary. */
static void pp_TyBound_C_ishly ( const XArray* tyents, UWord cuOff )
{
TyEnt* ent = ML_(TyEnts__index_by_cuOff)( tyents, NULL, cuOff );
if (!ent) {
VG_(printf)("**bounds-have-invalid-cuOff**");
return;
}
vg_assert(ent->tag == Te_Bound);
if (ent->Te.Bound.knownL && ent->Te.Bound.knownU
&& ent->Te.Bound.boundL == 0) {
VG_(printf)("[%lld]", 1 + ent->Te.Bound.boundU);
}
else
if (ent->Te.Bound.knownL && (!ent->Te.Bound.knownU)
&& ent->Te.Bound.boundL == 0) {
VG_(printf)("[]");
}
else
ML_(pp_TyEnt)( ent );
}
void ML_(pp_TyEnt_C_ishly)( const XArray* /* of TyEnt */ tyents,
UWord cuOff )
{
TyEnt* ent = ML_(TyEnts__index_by_cuOff)( tyents, NULL, cuOff );
if (!ent) {
VG_(printf)("**type-has-invalid-cuOff**");
return;
}
switch (ent->tag) {
case Te_TyBase:
if (!ent->Te.TyBase.name) goto unhandled;
VG_(printf)("%s", ent->Te.TyBase.name);
break;
case Te_TyPtr:
ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyPorR.typeR);
VG_(printf)("*");
break;
case Te_TyRef:
ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyPorR.typeR);
VG_(printf)("&");
break;
case Te_TyPtrMbr:
ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyPorR.typeR);
VG_(printf)("*");
break;
case Te_TyRvalRef:
ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyPorR.typeR);
VG_(printf)("&&");
break;
case Te_TyEnum:
VG_(printf)("enum %s", ent->Te.TyEnum.name ? ent->Te.TyEnum.name
: "<anonymous>" );
break;
case Te_TyStOrUn:
VG_(printf)("%s %s",
ent->Te.TyStOrUn.isStruct ? "struct" : "union",
ent->Te.TyStOrUn.name ? ent->Te.TyStOrUn.name
: "<anonymous>" );
break;
case Te_TyArray:
ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyArray.typeR);
if (ent->Te.TyArray.boundRs) {
Word w;
XArray* xa = ent->Te.TyArray.boundRs;
for (w = 0; w < VG_(sizeXA)(xa); w++) {
pp_TyBound_C_ishly( tyents, *(UWord*)VG_(indexXA)(xa, w) );
}
} else {
VG_(printf)("%s", "[??]");
}
break;
case Te_TyTyDef:
VG_(printf)("%s", ent->Te.TyTyDef.name ? ent->Te.TyTyDef.name
: "<anonymous>" );
break;
case Te_TyFn:
VG_(printf)("%s", "<function_type>");
break;
case Te_TyQual:
switch (ent->Te.TyQual.qual) {
case 'C': VG_(printf)("const "); break;
case 'V': VG_(printf)("volatile "); break;
case 'R': VG_(printf)("restrict "); break;
default: goto unhandled;
}
ML_(pp_TyEnt_C_ishly)(tyents, ent->Te.TyQual.typeR);
break;
case Te_TyVoid:
VG_(printf)("%svoid",
ent->Te.TyVoid.isFake ? "fake" : "");
break;
case Te_UNKNOWN:
ML_(pp_TyEnt)(ent);
break;
default:
goto unhandled;
}
return;
unhandled:
VG_(printf)("pp_TyEnt_C_ishly:unhandled: ");
ML_(pp_TyEnt)(ent);
vg_assert(0);
}
/* 'ents' is an XArray of TyEnts, sorted by their .cuOff fields. Find
the entry which has .cuOff field as specified. Returns NULL if not
found. Asserts if more than one entry has the specified .cuOff
value. */
void ML_(TyEntIndexCache__invalidate) ( TyEntIndexCache* cache )
{
Word i;
for (i = 0; i < N_TYENT_INDEX_CACHE; i++) {
cache->ce[i].cuOff0 = 0; /* not actually necessary */
cache->ce[i].ent0 = NULL; /* "invalid entry" */
cache->ce[i].cuOff1 = 0; /* not actually necessary */
cache->ce[i].ent1 = NULL; /* "invalid entry" */
}
}
TyEnt* ML_(TyEnts__index_by_cuOff) ( const XArray* /* of TyEnt */ ents,
TyEntIndexCache* cache,
UWord cuOff_to_find )
{
Bool found;
Word first, last;
TyEnt key, *res;
/* crude stats, aggregated over all caches */
static UWord cacheQs = 0 - 1;
static UWord cacheHits = 0;
if (0 && 0 == (cacheQs & 0xFFFF))
VG_(printf)("cache: %'lu queries, %'lu misses\n",
cacheQs, cacheQs - cacheHits);
if (LIKELY(cache != NULL)) {
UWord h = cuOff_to_find % (UWord)N_TYENT_INDEX_CACHE;
cacheQs++;
// dude, like, way 0, dude.
if (cache->ce[h].cuOff0 == cuOff_to_find && cache->ce[h].ent0 != NULL) {
// dude, way 0 is a total hit!
cacheHits++;
return cache->ce[h].ent0;
}
// dude, check out way 1, dude.
if (cache->ce[h].cuOff1 == cuOff_to_find && cache->ce[h].ent1 != NULL) {
// way 1 hit
UWord tc;
TyEnt* te;
cacheHits++;
// dude, way 1 is the new way 0. move with the times, dude.
tc = cache->ce[h].cuOff0;
te = cache->ce[h].ent0;
cache->ce[h].cuOff0 = cache->ce[h].cuOff1;
cache->ce[h].ent0 = cache->ce[h].ent1;
cache->ce[h].cuOff1 = tc;
cache->ce[h].ent1 = te;
return cache->ce[h].ent0;
}
}
/* We'll have to do it the hard way */
key.cuOff = cuOff_to_find;
key.tag = Te_EMPTY;
found = VG_(lookupXA)( ents, &key, &first, &last );
//found = VG_(lookupXA_UNBOXED)( ents, cuOff_to_find, &first, &last,
// offsetof(TyEnt,cuOff) );
if (!found)
return NULL;
/* If this fails, the array is invalid in the sense that there is
more than one entry with .cuOff == cuOff_to_find. */
vg_assert(first == last);
res = (TyEnt*)VG_(indexXA)( ents, first );
if (LIKELY(cache != NULL) && LIKELY(res != NULL)) {
/* this is a bit stupid, computing this twice. Oh well.
Perhaps some magic gcc transformation will common them up.
re "res != NULL", since .ent of NULL denotes 'invalid entry',
we can't cache the result when res == NULL. */
UWord h = cuOff_to_find % (UWord)N_TYENT_INDEX_CACHE;
cache->ce[h].cuOff1 = cache->ce[h].cuOff0;
cache->ce[h].ent1 = cache->ce[h].ent0;
cache->ce[h].cuOff0 = cuOff_to_find;
cache->ce[h].ent0 = res;
}
return res;
}
/* Generates a total ordering on TyEnts based only on their .cuOff
fields. */
Word ML_(TyEnt__cmp_by_cuOff_only) ( const TyEnt* te1, const TyEnt* te2 )
{
if (te1->cuOff < te2->cuOff) return -1;
if (te1->cuOff > te2->cuOff) return 1;
return 0;
}
/* Generates a total ordering on TyEnts based on everything except
their .cuOff fields. */
static inline Word UWord__cmp ( UWord a, UWord b ) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
static inline Word Long__cmp ( Long a, Long b ) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
static inline Word Bool__cmp ( Bool a, Bool b ) {
vg_assert( ((UWord)a) <= 1 );
vg_assert( ((UWord)b) <= 1 );
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
static inline Word UChar__cmp ( UChar a, UChar b ) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
static inline Word Int__cmp ( Int a, Int b ) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
static Word XArray_of_UWord__cmp ( const XArray* a, const XArray* b ) {
Word i, r;
Word aN = VG_(sizeXA)( a );
Word bN = VG_(sizeXA)( b );
if (aN < bN) return -1;
if (aN > bN) return 1;
for (i = 0; i < aN; i++) {
r = UWord__cmp( *(UWord*)VG_(indexXA)( a, i ),
*(UWord*)VG_(indexXA)( b, i ) );
if (r != 0) return r;
}
return 0;
}
static Word Bytevector__cmp ( const UChar* a, const UChar* b, Word n ) {
Word i, r;
vg_assert(n >= 0);
for (i = 0; i < n; i++) {
r = UChar__cmp( a[i], b[i] );
if (r != 0) return r;
}
return 0;
}
static Word Asciiz__cmp ( const HChar* a, const HChar* b ) {
/* A wrapper around strcmp that handles NULL strings safely. */
if (a == NULL && b == NULL) return 0;
if (a == NULL && b != NULL) return -1;
if (a != NULL && b == NULL) return 1;
return VG_(strcmp)(a, b);
}
Word ML_(TyEnt__cmp_by_all_except_cuOff) ( const TyEnt* te1, const TyEnt* te2 )
{
Word r;
if (te1->tag < te2->tag) return -1;
if (te1->tag > te2->tag) return 1;
switch (te1->tag) {
case Te_EMPTY:
return 0;
case Te_INDIR:
r = UWord__cmp(te1->Te.INDIR.indR, te2->Te.INDIR.indR);
return r;
case Te_Atom:
r = Bool__cmp(te1->Te.Atom.valueKnown, te2->Te.Atom.valueKnown);
if (r != 0) return r;
r = Long__cmp(te1->Te.Atom.value, te2->Te.Atom.value);
if (r != 0) return r;
r = Asciiz__cmp(te1->Te.Atom.name, te2->Te.Atom.name);
return r;
case Te_Field:
r = Bool__cmp(te1->Te.Field.isStruct, te2->Te.Field.isStruct);
if (r != 0) return r;
r = UWord__cmp(te1->Te.Field.typeR, te2->Te.Field.typeR);
if (r != 0) return r;
r = Asciiz__cmp(te1->Te.Field.name, te2->Te.Field.name);
if (r != 0) return r;
r = UWord__cmp(te1->Te.Field.nLoc, te2->Te.Field.nLoc);
if (r != 0) return r;
if (te1->Te.Field.nLoc == -1)
r = Long__cmp(te1->Te.Field.pos.offset, te2->Te.Field.pos.offset);
else
r = Bytevector__cmp(te1->Te.Field.pos.loc, te2->Te.Field.pos.loc,
te1->Te.Field.nLoc);
return r;
case Te_Bound:
r = Bool__cmp(te1->Te.Bound.knownL, te2->Te.Bound.knownL);
if (r != 0) return r;
r = Bool__cmp(te1->Te.Bound.knownU, te2->Te.Bound.knownU);
if (r != 0) return r;
r = Long__cmp(te1->Te.Bound.boundL, te2->Te.Bound.boundL);
if (r != 0) return r;
r = Long__cmp(te1->Te.Bound.boundU, te2->Te.Bound.boundU);
return r;
case Te_TyBase:
r = UChar__cmp(te1->Te.TyBase.enc, te2->Te.TyBase.enc);
if (r != 0) return r;
r = Int__cmp(te1->Te.TyBase.szB, te2->Te.TyBase.szB);
if (r != 0) return r;
r = Asciiz__cmp(te1->Te.TyBase.name, te2->Te.TyBase.name);
return r;
case Te_TyPtr:
case Te_TyRef:
case Te_TyPtrMbr:
case Te_TyRvalRef:
r = Int__cmp(te1->Te.TyPorR.szB, te2->Te.TyPorR.szB);
if (r != 0) return r;
r = UWord__cmp(te1->Te.TyPorR.typeR, te2->Te.TyPorR.typeR);
return r;
case Te_TyTyDef:
r = UWord__cmp(te1->Te.TyTyDef.typeR, te2->Te.TyTyDef.typeR);
if (r != 0) return r;
r = Asciiz__cmp(te1->Te.TyTyDef.name, te2->Te.TyTyDef.name);
return r;
case Te_TyStOrUn:
r = Bool__cmp(te1->Te.TyStOrUn.isStruct, te2->Te.TyStOrUn.isStruct);
if (r != 0) return r;
r = Bool__cmp(te1->Te.TyStOrUn.complete, te2->Te.TyStOrUn.complete);
if (r != 0) return r;
r = UWord__cmp(te1->Te.TyStOrUn.szB, te2->Te.TyStOrUn.szB);
if (r != 0) return r;
r = Asciiz__cmp(te1->Te.TyStOrUn.name, te2->Te.TyStOrUn.name);
if (r != 0) return r;
r = XArray_of_UWord__cmp(te1->Te.TyStOrUn.fieldRs,
te2->Te.TyStOrUn.fieldRs);
return r;
case Te_TyEnum:
r = Int__cmp(te1->Te.TyEnum.szB, te2->Te.TyEnum.szB);
if (r != 0) return r;
r = Asciiz__cmp(te1->Te.TyEnum.name, te2->Te.TyEnum.name);
if (r != 0) return r;
r = XArray_of_UWord__cmp(te1->Te.TyEnum.atomRs, te2->Te.TyEnum.atomRs);
return r;
case Te_TyArray:
r = UWord__cmp(te1->Te.TyArray.typeR, te2->Te.TyArray.typeR);
if (r != 0) return r;
r = XArray_of_UWord__cmp(te1->Te.TyArray.boundRs,
te2->Te.TyArray.boundRs);
return r;
case Te_TyFn:
return 0;
case Te_TyQual:
r = UWord__cmp(te1->Te.TyQual.typeR, te2->Te.TyQual.typeR);
if (r != 0) return r;
r = UChar__cmp(te1->Te.TyQual.qual, te2->Te.TyQual.qual);
return r;
case Te_TyVoid:
r = Bool__cmp(te1->Te.TyVoid.isFake, te2->Te.TyVoid.isFake);
return r;
default:
vg_assert(0);
}
}
/* Free up all directly or indirectly heap-allocated stuff attached to
this TyEnt, and set its tag to Te_EMPTY. The .cuOff field is
unchanged. */
void ML_(TyEnt__make_EMPTY) ( TyEnt* te )
{
UWord saved_cuOff;
/* First, free up any fields in mallocville. */
switch (te->tag) {
case Te_EMPTY:
break;
case Te_INDIR:
break;
case Te_UNKNOWN:
break;
case Te_Atom:
if (te->Te.Atom.name) ML_(dinfo_free)(te->Te.Atom.name);
break;
case Te_Field:
if (te->Te.Field.name) ML_(dinfo_free)(te->Te.Field.name);
if (te->Te.Field.nLoc > 0 && te->Te.Field.pos.loc)
ML_(dinfo_free)(te->Te.Field.pos.loc);
break;
case Te_Bound:
break;
case Te_TyBase:
if (te->Te.TyBase.name) ML_(dinfo_free)(te->Te.TyBase.name);
break;
case Te_TyPtr:
case Te_TyRef:
case Te_TyPtrMbr:
case Te_TyRvalRef:
break;
case Te_TyTyDef:
if (te->Te.TyTyDef.name) ML_(dinfo_free)(te->Te.TyTyDef.name);
break;
case Te_TyStOrUn:
if (te->Te.TyStOrUn.name) ML_(dinfo_free)(te->Te.TyStOrUn.name);
VG_(deleteXA)(te->Te.TyStOrUn.fieldRs);
break;
case Te_TyEnum:
if (te->Te.TyEnum.name) ML_(dinfo_free)(te->Te.TyEnum.name);
if (te->Te.TyEnum.atomRs) VG_(deleteXA)(te->Te.TyEnum.atomRs);
break;
case Te_TyArray:
if (te->Te.TyArray.boundRs) VG_(deleteXA)(te->Te.TyArray.boundRs);
break;
case Te_TyFn:
break;
case Te_TyQual:
break;
case Te_TyVoid:
break;
default:
vg_assert(0);
}
/* Now clear it out and set to Te_EMPTY. */
saved_cuOff = te->cuOff;
VG_(memset)(te, 0, sizeof(*te));
te->cuOff = saved_cuOff;
te->tag = Te_EMPTY;
}
/* How big is this type? If .b in the returned struct is False, the
size is unknown. */
static MaybeULong mk_MaybeULong_Nothing ( void ) {
MaybeULong mul;
mul.ul = 0;
mul.b = False;
return mul;
}
static MaybeULong mk_MaybeULong_Just ( ULong ul ) {
MaybeULong mul;
mul.ul = ul;
mul.b = True;
return mul;
}
static MaybeULong mul_MaybeULong ( MaybeULong mul1, MaybeULong mul2 ) {
if (!mul1.b) { vg_assert(mul1.ul == 0); return mul1; }
if (!mul2.b) { vg_assert(mul2.ul == 0); return mul2; }
mul1.ul *= mul2.ul;
return mul1;
}
MaybeULong ML_(sizeOfType)( const XArray* /* of TyEnt */ tyents,
UWord cuOff )
{
Word i;
MaybeULong eszB;
TyEnt* ent = ML_(TyEnts__index_by_cuOff)(tyents, NULL, cuOff);
TyEnt* ent2;
vg_assert(ent);
vg_assert(ML_(TyEnt__is_type)(ent));
switch (ent->tag) {
case Te_TyBase:
vg_assert(ent->Te.TyBase.szB > 0);
return mk_MaybeULong_Just( ent->Te.TyBase.szB );
case Te_TyQual:
return ML_(sizeOfType)( tyents, ent->Te.TyQual.typeR );
case Te_TyTyDef:
ent2 = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
ent->Te.TyTyDef.typeR);
vg_assert(ent2);
if (ent2->tag == Te_UNKNOWN)
return mk_MaybeULong_Nothing(); /*UNKNOWN*/
return ML_(sizeOfType)( tyents, ent->Te.TyTyDef.typeR );
case Te_TyPtr:
case Te_TyRef:
case Te_TyPtrMbr:
case Te_TyRvalRef:
vg_assert(ent->Te.TyPorR.szB == 4 || ent->Te.TyPorR.szB == 8);
return mk_MaybeULong_Just( ent->Te.TyPorR.szB );
case Te_TyStOrUn:
return ent->Te.TyStOrUn.complete
? mk_MaybeULong_Just( ent->Te.TyStOrUn.szB )
: mk_MaybeULong_Nothing();
case Te_TyEnum:
return mk_MaybeULong_Just( ent->Te.TyEnum.szB );
case Te_TyArray:
ent2 = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
ent->Te.TyArray.typeR);
vg_assert(ent2);
if (ent2->tag == Te_UNKNOWN)
return mk_MaybeULong_Nothing(); /*UNKNOWN*/
eszB = ML_(sizeOfType)( tyents, ent->Te.TyArray.typeR );
for (i = 0; i < VG_(sizeXA)( ent->Te.TyArray.boundRs ); i++) {
UWord bo_cuOff
= *(UWord*)VG_(indexXA)(ent->Te.TyArray.boundRs, i);
TyEnt* bo
= ML_(TyEnts__index_by_cuOff)( tyents, NULL, bo_cuOff );
vg_assert(bo);
vg_assert(bo->tag == Te_Bound);
if (!(bo->Te.Bound.knownL && bo->Te.Bound.knownU))
return mk_MaybeULong_Nothing(); /*UNKNOWN*/
eszB = mul_MaybeULong(
eszB,
mk_MaybeULong_Just( (ULong)(bo->Te.Bound.boundU
- bo->Te.Bound.boundL + 1) ));
}
return eszB;
case Te_TyVoid:
return mk_MaybeULong_Nothing(); /*UNKNOWN*/
default:
VG_(printf)("ML_(sizeOfType): unhandled: ");
ML_(pp_TyEnt)(ent);
VG_(printf)("\n");
vg_assert(0);
}
}
/* Describe where in the type 'offset' falls. Caller must
deallocate the resulting XArray. */
static void copy_UWord_into_XA ( XArray* /* of HChar */ xa,
UWord uw ) {
HChar buf[32]; // large enough
VG_(sprintf)(buf, "%lu", uw);
VG_(addBytesToXA)( xa, buf, VG_(strlen)(buf));
}
XArray* /*HChar*/ ML_(describe_type)( /*OUT*/PtrdiffT* residual_offset,
const XArray* /* of TyEnt */ tyents,
UWord ty_cuOff,
PtrdiffT offset )
{
TyEnt* ty;
XArray* xa = VG_(newXA)( ML_(dinfo_zalloc), "di.tytypes.dt.1",
ML_(dinfo_free),
sizeof(HChar) );
ty = ML_(TyEnts__index_by_cuOff)(tyents, NULL, ty_cuOff);
while (True) {
vg_assert(ty);
vg_assert(ML_(TyEnt__is_type)(ty));
switch (ty->tag) {
/* These are all atomic types; there is nothing useful we can
do. */
case Te_TyEnum:
case Te_TyFn:
case Te_TyVoid:
case Te_TyPtr:
case Te_TyRef:
case Te_TyPtrMbr:
case Te_TyRvalRef:
case Te_TyBase:
goto done;
case Te_TyStOrUn: {
Word i;
GXResult res;
MaybeULong mul;
XArray* fieldRs;
UWord fieldR;
TyEnt* field = NULL;
PtrdiffT offMin = 0, offMax1 = 0;
if (!ty->Te.TyStOrUn.isStruct) goto done;
fieldRs = ty->Te.TyStOrUn.fieldRs;
if (VG_(sizeXA)(fieldRs) == 0
&& (ty->Te.TyStOrUn.typeR == 0)) goto done;
for (i = 0; i < VG_(sizeXA)( fieldRs ); i++ ) {
fieldR = *(UWord*)VG_(indexXA)( fieldRs, i );
field = ML_(TyEnts__index_by_cuOff)(tyents, NULL, fieldR);
vg_assert(field);
vg_assert(field->tag == Te_Field);
vg_assert(field->Te.Field.nLoc < 0
|| (field->Te.Field.nLoc > 0
&& field->Te.Field.pos.loc));
if (field->Te.Field.nLoc == -1) {
res.kind = GXR_Addr;
res.word = field->Te.Field.pos.offset;
} else {
/* Re data_bias in this call, we should really send in
a legitimate value. But the expression is expected
to be a constant expression, evaluation of which
will not need to use DW_OP_addr and hence we can
avoid the trouble of plumbing the data bias through
to this point (if, indeed, it has any meaning; from
which DebugInfo would we take the data bias? */
res = ML_(evaluate_Dwarf3_Expr)(
field->Te.Field.pos.loc, field->Te.Field.nLoc,
NULL/*fbGX*/, NULL/*RegSummary*/,
0/*data_bias*/,
True/*push_initial_zero*/);
if (0) {
VG_(printf)("QQQ ");
ML_(pp_GXResult)(res);
VG_(printf)("\n");
}
}
if (res.kind != GXR_Addr)
continue;
mul = ML_(sizeOfType)( tyents, field->Te.Field.typeR );
if (mul.b != True)
goto done; /* size of field is unknown (?!) */
offMin = res.word;
offMax1 = offMin + (PtrdiffT)mul.ul;
if (offMin == offMax1)
continue;
vg_assert(offMin < offMax1);
if (offset >= offMin && offset < offMax1)
break;
}
/* Did we find a suitable field? */
vg_assert(i >= 0 && i <= VG_(sizeXA)( fieldRs ));
if (i == VG_(sizeXA)( fieldRs )) {
ty = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
ty->Te.TyStOrUn.typeR);
vg_assert(ty);
if (ty->tag == Te_UNKNOWN) goto done;
vg_assert(ML_(TyEnt__is_type)(ty));
continue;
}
/* Yes. 'field' is it. */
vg_assert(field);
if (!field->Te.Field.name) goto done;
VG_(addBytesToXA)( xa, ".", 1 );
VG_(addBytesToXA)( xa, field->Te.Field.name,
VG_(strlen)(field->Te.Field.name) );
offset -= offMin;
ty = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
field->Te.Field.typeR );
vg_assert(ty);
if (ty->tag == Te_UNKNOWN) goto done;
/* keep going; look inside the field. */
break;
}
case Te_TyArray: {
MaybeULong mul;
UWord size, eszB, ix;
UWord boundR;
TyEnt* elemTy;
TyEnt* bound;
/* Just deal with the simple, common C-case: 1-D array,
zero based, known size. */
elemTy = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
ty->Te.TyArray.typeR);
vg_assert(elemTy);
if (elemTy->tag == Te_UNKNOWN) goto done;
vg_assert(ML_(TyEnt__is_type)(elemTy));
if (!ty->Te.TyArray.boundRs)
goto done;
if (VG_(sizeXA)( ty->Te.TyArray.boundRs ) != 1) goto done;
boundR = *(UWord*)VG_(indexXA)( ty->Te.TyArray.boundRs, 0 );
bound = ML_(TyEnts__index_by_cuOff)(tyents, NULL, boundR);
vg_assert(bound);
vg_assert(bound->tag == Te_Bound);
if (!(bound->Te.Bound.knownL && bound->Te.Bound.knownU
&& bound->Te.Bound.boundL == 0
&& bound->Te.Bound.boundU >= bound->Te.Bound.boundL))
goto done;
size = bound->Te.Bound.boundU - bound->Te.Bound.boundL + 1;
vg_assert(size >= 1);
mul = ML_(sizeOfType)( tyents, ty->Te.TyArray.typeR );
if (mul.b != True)
goto done; /* size of element type not known */
eszB = mul.ul;
if (eszB == 0) goto done;
ix = offset / eszB;
VG_(addBytesToXA)( xa, "[", 1 );
copy_UWord_into_XA( xa, ix );
VG_(addBytesToXA)( xa, "]", 1 );
ty = elemTy;
offset -= ix * eszB;
/* keep going; look inside the array element. */
break;
}
case Te_TyQual: {
ty = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
ty->Te.TyQual.typeR);
vg_assert(ty);
if (ty->tag == Te_UNKNOWN) goto done;
break;
}
case Te_TyTyDef: {
ty = ML_(TyEnts__index_by_cuOff)(tyents, NULL,
ty->Te.TyTyDef.typeR);
vg_assert(ty);
if (ty->tag == Te_UNKNOWN) goto done;
break;
}
default: {
VG_(printf)("ML_(describe_type): unhandled: ");
ML_(pp_TyEnt)(ty);
VG_(printf)("\n");
vg_assert(0);
}
}
}
done:
*residual_offset = offset;
VG_(addBytesToXA)( xa, "\0", 1 );
return xa;
}
/*--------------------------------------------------------------------*/
/*--- end tytypes.c ---*/
/*--------------------------------------------------------------------*/