forked from Imagelibrary/binutils-gdb
libctf: split out compatibility code
The compatibility-opening code is quite voluminous, and is stuck right in the middle of ctf-open.c, rather interfering with maintenance. Split it out into a new ctf-open-compat.c. (Since it is not yet upgraded to support v4, the new file is not added to the build system yet: indeed, even the calls to it haven't been diked out at this stage.)
This commit is contained in:
@@ -384,325 +384,7 @@ ctf_set_base (ctf_dict_t *fp, const ctf_header_t *hp, unsigned char *base)
|
||||
ctf_dprintf ("ctf_set_base: parent name %s (label %s)\n",
|
||||
fp->ctf_parname,
|
||||
fp->ctf_parlabel ? fp->ctf_parlabel : "<NULL>");
|
||||
}
|
||||
|
||||
/* Set the version of the CTF file. */
|
||||
|
||||
/* When this is reset, LCTF_* changes behaviour, but there is no guarantee that
|
||||
the variable data list associated with each type has been upgraded: the
|
||||
caller must ensure this has been done in advance. */
|
||||
|
||||
static void
|
||||
ctf_set_version (ctf_dict_t *fp, ctf_header_t *cth, int ctf_version)
|
||||
{
|
||||
fp->ctf_version = ctf_version;
|
||||
cth->cth_version = ctf_version;
|
||||
fp->ctf_dictops = &ctf_dictops[ctf_version];
|
||||
}
|
||||
|
||||
|
||||
/* Upgrade the header to CTF_VERSION_4. The upgrade is done in-place,
|
||||
end-to-start. */
|
||||
static void
|
||||
upgrade_header_v2 (ctf_header_t *hp)
|
||||
{
|
||||
ctf_header_v2_t *oldhp = (ctf_header_v2_t *) hp;
|
||||
|
||||
hp->cth_strlen = oldhp->cth_strlen;
|
||||
hp->cth_stroff = oldhp->cth_stroff;
|
||||
hp->cth_typeoff = oldhp->cth_typeoff;
|
||||
hp->cth_varoff = oldhp->cth_varoff;
|
||||
hp->cth_funcidxoff = hp->cth_varoff; /* No index sections. */
|
||||
hp->cth_objtidxoff = hp->cth_funcidxoff;
|
||||
hp->cth_funcoff = oldhp->cth_funcoff;
|
||||
hp->cth_objtoff = oldhp->cth_objtoff;
|
||||
hp->cth_lbloff = oldhp->cth_lbloff;
|
||||
hp->cth_parent_strlen = 0; /* Strings start at offset 0. */
|
||||
hp->cth_cuname = 0; /* No CU name. */
|
||||
}
|
||||
|
||||
/* Ditto, for CTFv3. */
|
||||
static void
|
||||
upgrade_header_v3 (ctf_header_t *hp)
|
||||
{
|
||||
ctf_header_v3_t *oldhp = (ctf_header_v3_t *) hp;
|
||||
|
||||
hp->cth_strlen = oldhp->cth_strlen;
|
||||
hp->cth_stroff = oldhp->cth_stroff;
|
||||
hp->cth_typeoff = oldhp->cth_typeoff;
|
||||
hp->cth_varoff = oldhp->cth_varoff;
|
||||
hp->cth_funcidxoff = oldhp->cth_funcidxoff;
|
||||
hp->cth_objtidxoff = oldhp->cth_objtidxoff;
|
||||
hp->cth_funcoff = oldhp->cth_funcoff;
|
||||
hp->cth_objtoff = oldhp->cth_objtoff;
|
||||
hp->cth_lbloff = oldhp->cth_lbloff;
|
||||
hp->cth_parent_strlen = 0; /* Strings start at offset 0. */
|
||||
hp->cth_cuname = oldhp->cth_cuname;
|
||||
hp->cth_parname = oldhp->cth_parname;
|
||||
hp->cth_parlabel = oldhp->cth_parlabel;
|
||||
}
|
||||
|
||||
/* Upgrade the type table to CTF_VERSION_3 (really CTF_VERSION_1_UPGRADED_3)
|
||||
from CTF_VERSION_1.
|
||||
|
||||
The upgrade is not done in-place: the ctf_base is moved. ctf_strptr() must
|
||||
not be called before reallocation is complete.
|
||||
|
||||
Sections not checked here due to nonexistence or nonpopulated state in older
|
||||
formats: objtidx, funcidx.
|
||||
|
||||
Type kinds not checked here due to nonexistence in older formats:
|
||||
CTF_K_SLICE. */
|
||||
static int
|
||||
upgrade_types_v1 (ctf_dict_t *fp, ctf_header_t *cth)
|
||||
{
|
||||
const ctf_type_v1_t *tbuf;
|
||||
const ctf_type_v1_t *tend;
|
||||
unsigned char *ctf_base, *old_ctf_base = (unsigned char *) fp->ctf_dynbase;
|
||||
ctf_type_t *t2buf;
|
||||
|
||||
ssize_t increase = 0, size, increment, v2increment, vbytes, v2bytes;
|
||||
const ctf_type_v1_t *tp;
|
||||
ctf_type_t *t2p;
|
||||
|
||||
tbuf = (ctf_type_v1_t *) (fp->ctf_buf + cth->cth_typeoff);
|
||||
tend = (ctf_type_v1_t *) (fp->ctf_buf + cth->cth_stroff);
|
||||
|
||||
/* This is a two-pass process.
|
||||
|
||||
First, figure out the new type-section size needed. (It is possible,
|
||||
in theory, for it to be less than the old size, but this is very
|
||||
unlikely. It cannot be so small that cth_typeoff ends up of negative
|
||||
size. We validate this with an assertion below.)
|
||||
|
||||
We must cater not only for changes in vlen and types sizes but also
|
||||
for changes in 'increment', which happen because v2 places some types
|
||||
into ctf_stype_t where v1 would be forced to use the larger non-stype. */
|
||||
|
||||
for (tp = tbuf; tp < tend;
|
||||
tp = (ctf_type_v1_t *) ((uintptr_t) tp + increment + vbytes))
|
||||
{
|
||||
unsigned short kind = CTF_V1_INFO_KIND (tp->ctt_info);
|
||||
unsigned long vlen = CTF_V1_INFO_VLEN (tp->ctt_info);
|
||||
|
||||
size = get_ctt_size_v1 (fp, (const ctf_type_t *) tp, NULL, &increment);
|
||||
vbytes = get_vbytes_v1 (fp, kind, size, vlen);
|
||||
|
||||
get_ctt_size_v2_unconverted (fp, (const ctf_type_t *) tp, NULL,
|
||||
&v2increment);
|
||||
v2bytes = get_vbytes_v2 (fp, kind, size, vlen);
|
||||
|
||||
if ((vbytes < 0) || (size < 0))
|
||||
return ECTF_CORRUPT;
|
||||
|
||||
increase += v2increment - increment; /* May be negative. */
|
||||
increase += v2bytes - vbytes;
|
||||
}
|
||||
|
||||
/* Allocate enough room for the new buffer, then copy everything but the type
|
||||
section into place, and reset the base accordingly. Leave the version
|
||||
number unchanged, so that LCTF_INFO_* still works on the
|
||||
as-yet-untranslated type info. */
|
||||
|
||||
if ((ctf_base = malloc (fp->ctf_size + increase)) == NULL)
|
||||
return ECTF_ZALLOC;
|
||||
|
||||
/* Start at ctf_buf, not ctf_base, to squeeze out the original header: we
|
||||
never use it and it is unconverted. */
|
||||
|
||||
memcpy (ctf_base, fp->ctf_buf, cth->cth_typeoff);
|
||||
memcpy (ctf_base + cth->cth_stroff + increase,
|
||||
fp->ctf_buf + cth->cth_stroff, cth->cth_strlen);
|
||||
|
||||
memset (ctf_base + cth->cth_typeoff, 0, cth->cth_stroff - cth->cth_typeoff
|
||||
+ increase);
|
||||
|
||||
cth->cth_stroff += increase;
|
||||
fp->ctf_size += increase;
|
||||
assert (cth->cth_stroff >= cth->cth_typeoff);
|
||||
fp->ctf_base = ctf_base;
|
||||
fp->ctf_buf = ctf_base;
|
||||
fp->ctf_dynbase = ctf_base;
|
||||
ctf_set_base (fp, cth, ctf_base);
|
||||
|
||||
t2buf = (ctf_type_t *) (fp->ctf_buf + cth->cth_typeoff);
|
||||
|
||||
/* Iterate through all the types again, upgrading them.
|
||||
|
||||
Everything that hasn't changed can just be outright memcpy()ed.
|
||||
Things that have changed need field-by-field consideration. */
|
||||
|
||||
for (tp = tbuf, t2p = t2buf; tp < tend;
|
||||
tp = (ctf_type_v1_t *) ((uintptr_t) tp + increment + vbytes),
|
||||
t2p = (ctf_type_t *) ((uintptr_t) t2p + v2increment + v2bytes))
|
||||
{
|
||||
unsigned short kind = CTF_V1_INFO_KIND (tp->ctt_info);
|
||||
int isroot = CTF_V1_INFO_ISROOT (tp->ctt_info);
|
||||
unsigned long vlen = CTF_V1_INFO_VLEN (tp->ctt_info);
|
||||
ssize_t v2size;
|
||||
void *vdata, *v2data;
|
||||
|
||||
size = get_ctt_size_v1 (fp, (const ctf_type_t *) tp, NULL, &increment);
|
||||
vbytes = get_vbytes_v1 (fp, kind, size, vlen);
|
||||
|
||||
t2p->ctt_name = tp->ctt_name;
|
||||
t2p->ctt_info = CTF_TYPE_INFO (kind, isroot, vlen);
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case CTF_K_FUNCTION:
|
||||
case CTF_K_FORWARD:
|
||||
case CTF_K_TYPEDEF:
|
||||
case CTF_K_POINTER:
|
||||
case CTF_K_VOLATILE:
|
||||
case CTF_K_CONST:
|
||||
case CTF_K_RESTRICT:
|
||||
t2p->ctt_type = tp->ctt_type;
|
||||
break;
|
||||
case CTF_K_INTEGER:
|
||||
case CTF_K_FLOAT:
|
||||
case CTF_K_ARRAY:
|
||||
case CTF_K_STRUCT:
|
||||
case CTF_K_UNION:
|
||||
case CTF_K_ENUM:
|
||||
case CTF_K_UNKNOWN:
|
||||
if ((size_t) size <= CTF_MAX_SIZE)
|
||||
t2p->ctt_size = size;
|
||||
else
|
||||
{
|
||||
t2p->ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
|
||||
t2p->ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
v2size = get_ctt_size_v2 (fp, t2p, NULL, &v2increment);
|
||||
v2bytes = get_vbytes_v2 (fp, kind, v2size, vlen);
|
||||
|
||||
/* Catch out-of-sync get_ctt_size_*(). The count goes wrong if
|
||||
these are not identical (and having them different makes no
|
||||
sense semantically). */
|
||||
|
||||
assert (size == v2size);
|
||||
|
||||
/* Now the varlen info. */
|
||||
|
||||
vdata = (void *) ((uintptr_t) tp + increment);
|
||||
v2data = (void *) ((uintptr_t) t2p + v2increment);
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case CTF_K_ARRAY:
|
||||
{
|
||||
const ctf_array_v1_t *ap = (const ctf_array_v1_t *) vdata;
|
||||
ctf_array_t *a2p = (ctf_array_t *) v2data;
|
||||
|
||||
a2p->cta_contents = ap->cta_contents;
|
||||
a2p->cta_index = ap->cta_index;
|
||||
a2p->cta_nelems = ap->cta_nelems;
|
||||
break;
|
||||
}
|
||||
case CTF_K_STRUCT:
|
||||
case CTF_K_UNION:
|
||||
{
|
||||
ctf_member_t tmp;
|
||||
const ctf_member_v1_t *m1 = (const ctf_member_v1_t *) vdata;
|
||||
const ctf_lmember_v1_t *lm1 = (const ctf_lmember_v1_t *) m1;
|
||||
ctf_member_t *m2 = (ctf_member_t *) v2data;
|
||||
ctf_lmember_t *lm2 = (ctf_lmember_t *) m2;
|
||||
unsigned long i;
|
||||
|
||||
/* We walk all four pointers forward, but only reference the two
|
||||
that are valid for the given size, to avoid quadruplicating all
|
||||
the code. */
|
||||
|
||||
for (i = vlen; i != 0; i--, m1++, lm1++, m2++, lm2++)
|
||||
{
|
||||
size_t offset;
|
||||
if (size < CTF_LSTRUCT_THRESH_V1)
|
||||
{
|
||||
offset = m1->ctm_offset;
|
||||
tmp.ctm_name = m1->ctm_name;
|
||||
tmp.ctm_type = m1->ctm_type;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = CTF_LMEM_OFFSET (lm1);
|
||||
tmp.ctm_name = lm1->ctlm_name;
|
||||
tmp.ctm_type = lm1->ctlm_type;
|
||||
}
|
||||
if (size < CTF_LSTRUCT_THRESH)
|
||||
{
|
||||
m2->ctm_name = tmp.ctm_name;
|
||||
m2->ctm_type = tmp.ctm_type;
|
||||
m2->ctm_offset = offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
lm2->ctlm_name = tmp.ctm_name;
|
||||
lm2->ctlm_type = tmp.ctm_type;
|
||||
lm2->ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (offset);
|
||||
lm2->ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (offset);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CTF_K_FUNCTION:
|
||||
{
|
||||
unsigned long i;
|
||||
unsigned short *a1 = (unsigned short *) vdata;
|
||||
uint32_t *a2 = (uint32_t *) v2data;
|
||||
|
||||
for (i = vlen; i != 0; i--, a1++, a2++)
|
||||
*a2 = *a1;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
default:
|
||||
/* Catch out-of-sync get_vbytes_*(). */
|
||||
assert (vbytes == v2bytes);
|
||||
memcpy (v2data, vdata, vbytes);
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that the entire region was converted. If not, we are either
|
||||
converting too much, or too little (leading to a buffer overrun either here
|
||||
or at read time, in init_static_types().) */
|
||||
|
||||
assert ((size_t) t2p - (size_t) fp->ctf_buf == cth->cth_stroff);
|
||||
|
||||
ctf_set_version (fp, cth, CTF_VERSION_1_UPGRADED_3);
|
||||
free (old_ctf_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Upgrade from any earlier version. */
|
||||
static int
|
||||
upgrade_types (ctf_dict_t *fp, ctf_header_t *cth)
|
||||
{
|
||||
switch (cth->cth_version)
|
||||
{
|
||||
/* v1 requires a full pass and reformatting. */
|
||||
case CTF_VERSION_1:
|
||||
upgrade_types_v1 (fp, cth);
|
||||
/* FALLTHRU */
|
||||
/* Already-converted v1 is just like later versions except that its
|
||||
parent/child boundary is unchanged (and much lower). */
|
||||
|
||||
case CTF_VERSION_1_UPGRADED_3:
|
||||
fp->ctf_header->cth_parent_typemax = CTF_MAX_PTYPE_V1;
|
||||
break;
|
||||
|
||||
/* v2 and v3 are currently just the same as v4 except for new types and
|
||||
sections: no upgrading required.
|
||||
|
||||
UPTODO: this is really going to change. */
|
||||
case CTF_VERSION_2: ;
|
||||
case CTF_VERSION_3: ;
|
||||
fp->ctf_header->cth_parent_typemax = CTF_MAX_PTYPE;
|
||||
/* FALLTHRU */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
Reference in New Issue
Block a user