dbghelp: Fieldlist.

- now that we have offset tables to type, we can cleanly
  parse the field-lists and remove the associated kludges
- also adding internal structure for easing parameter sharing
  across functions (codeview_type_parse)
- in mscvpdb.h, also reparated the type records that are
  referenced from other type records (union codeview_type_ref)
  from type records referenced by symbols (union codeview_type)
This commit is contained in:
Eric Pouech 2006-03-18 13:32:50 +01:00 committed by Alexandre Julliard
parent 633ab584c1
commit 4c2cec5553
2 changed files with 120 additions and 118 deletions

View File

@ -4,7 +4,7 @@
*
* Copyright (C) 1996, Eric Youngdale.
* Copyright (C) 1999-2000, Ulrich Weigand.
* Copyright (C) 2004-2005, Eric Pouech.
* Copyright (C) 2004-2006, Eric Pouech.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -328,6 +328,21 @@ static struct symt* codeview_get_type(unsigned int typeno, BOOL allow_special)
return symt;
}
struct codeview_type_parse
{
struct module* module;
const BYTE* table;
const DWORD* offset;
DWORD num;
};
static inline const void* codeview_jump_to_type(struct codeview_type_parse* ctp, DWORD idx)
{
if (idx < FIRST_DEFINABLE_TYPE) return NULL;
idx -= FIRST_DEFINABLE_TYPE;
return (idx >= ctp->num) ? NULL : (ctp->table + ctp->offset[idx]);
}
static int codeview_add_type(unsigned int typeno, struct symt* dt)
{
if (typeno < FIRST_DEFINABLE_TYPE)
@ -438,23 +453,23 @@ static int codeview_add_type_bitfield(unsigned int typeno, unsigned int bitoff,
}
static int codeview_add_type_enum_field_list(struct module* module,
unsigned int typeno,
const unsigned char* list, int len)
struct symt_enum* symt,
const union codeview_reftype* ref_type)
{
struct symt_enum* symt;
const unsigned char* ptr = list;
const unsigned char* ptr = ref_type->fieldlist.list;
const unsigned char* last = (const BYTE*)ref_type + ref_type->generic.len + 2;
const union codeview_fieldtype* type;
symt = symt_new_enum(module, NULL);
while (ptr - list < len)
while (ptr < last)
{
const union codeview_fieldtype* type = (const union codeview_fieldtype*)ptr;
if (*ptr >= 0xf0) /* LF_PAD... */
{
ptr += *ptr & 0x0f;
continue;
}
type = (const union codeview_fieldtype*)ptr;
switch (type->generic.id)
{
case LF_ENUMERATE_V1:
@ -481,32 +496,31 @@ static int codeview_add_type_enum_field_list(struct module* module,
return FALSE;
}
}
return codeview_add_type(typeno, &symt->symt);
return TRUE;
}
static int codeview_add_type_struct_field_list(struct module* module,
unsigned int typeno,
const unsigned char* list, int len)
struct symt_udt* symt,
const union codeview_reftype* ref_type)
{
struct symt_udt* symt;
const unsigned char* ptr = list;
const unsigned char* ptr = ref_type->fieldlist.list;
const unsigned char* last = (const BYTE*)ref_type + ref_type->generic.len + 2;
int value, leaf_len;
const struct p_string* p_name;
const char* c_name;
struct symt* subtype;
const union codeview_fieldtype* type;
symt = symt_new_udt(module, NULL, 0, UdtStruct /* don't care */);
while (ptr - list < len)
while (ptr < last)
{
const union codeview_fieldtype* type = (const union codeview_fieldtype*)ptr;
if (*ptr >= 0xf0) /* LF_PAD... */
{
ptr += *ptr & 0x0f;
continue;
}
type = (const union codeview_fieldtype*)ptr;
switch (type->generic.id)
{
case LF_BCLASS_V1:
@ -699,31 +713,26 @@ static int codeview_add_type_struct_field_list(struct module* module,
}
}
return codeview_add_type(typeno, &symt->symt);
return TRUE;
}
static int codeview_add_type_enum(struct module* module, unsigned int typeno,
const char* name, unsigned int fieldlist)
const char* name, const union codeview_reftype* fieldlist)
{
struct symt_enum* symt = symt_new_enum(module, name);
struct symt* list = codeview_get_type(fieldlist, FALSE);
/* FIXME: this is rather ugly !!! */
if (list) symt->vchildren = ((struct symt_enum*)list)->vchildren;
if (fieldlist) codeview_add_type_enum_field_list(module, symt, fieldlist);
return codeview_add_type(typeno, &symt->symt);
}
static int codeview_add_type_struct(struct module* module, unsigned int typeno,
const char* name, int structlen,
unsigned int fieldlist, enum UdtKind kind)
const union codeview_reftype* fieldlist,
enum UdtKind kind)
{
struct symt_udt* symt = symt_new_udt(module, name, structlen, kind);
struct symt* list = codeview_get_type(fieldlist, FALSE);
/* FIXME: this is rather ugly !!! */
if (list) symt->vchildren = ((struct symt_udt*)list)->vchildren;
if (fieldlist) codeview_add_type_struct_field_list(module, symt, fieldlist);
return codeview_add_type(typeno, &symt->symt);
}
@ -737,20 +746,20 @@ static int codeview_new_func_signature(struct module* module, unsigned typeno,
return codeview_add_type(typeno, symt);
}
static int codeview_parse_type_table(struct module* module, const BYTE* table,
const DWORD* offset, DWORD num)
static int codeview_parse_type_table(struct codeview_type_parse* ctp)
{
unsigned int curr_type = 0x1000;
unsigned int curr_type = FIRST_DEFINABLE_TYPE;
int retv = TRUE;
const union codeview_type* type;
const union codeview_reftype*type_ref;
int value, leaf_len;
const struct p_string* p_name;
const char* c_name;
for (curr_type = 0x1000; retv && curr_type < 0x1000 + num; curr_type++)
for (curr_type = FIRST_DEFINABLE_TYPE; retv && curr_type < FIRST_DEFINABLE_TYPE + ctp->num; curr_type++)
{
retv = TRUE;
type = (const union codeview_type*)(table + offset[curr_type - 0x1000]);
type = codeview_jump_to_type(ctp, curr_type);
/* type records we're interested in are the ones referenced by symbols
* The known ranges are (X mark the ones we want):
@ -765,9 +774,7 @@ static int codeview_parse_type_table(struct module* module, const BYTE* table,
*/
if ((type->generic.id & 0x8600) &&
type->generic.id != LF_BITFIELD_V1 && /* still some cases to fix */
type->generic.id != LF_BITFIELD_V2 &&
type->generic.id != LF_FIELDLIST_V1 &&
type->generic.id != LF_FIELDLIST_V2)
type->generic.id != LF_BITFIELD_V2)
continue;
switch (type->generic.id)
{
@ -797,11 +804,11 @@ static int codeview_parse_type_table(struct module* module, const BYTE* table,
break;
case LF_POINTER_V1:
retv = codeview_add_type_pointer(module, curr_type,
retv = codeview_add_type_pointer(ctp->module, curr_type,
type->pointer_v1.datatype);
break;
case LF_POINTER_V2:
retv = codeview_add_type_pointer(module, curr_type,
retv = codeview_add_type_pointer(ctp->module, curr_type,
type->pointer_v2.datatype);
break;
@ -809,21 +816,21 @@ static int codeview_parse_type_table(struct module* module, const BYTE* table,
leaf_len = numeric_leaf(&value, &type->array_v1.arrlen);
p_name = (const struct p_string*)((const unsigned char*)&type->array_v1.arrlen + leaf_len);
retv = codeview_add_type_array(module, curr_type, terminate_string(p_name),
retv = codeview_add_type_array(ctp->module, curr_type, terminate_string(p_name),
type->array_v1.elemtype, type->array_v1.idxtype, value);
break;
case LF_ARRAY_V2:
leaf_len = numeric_leaf(&value, &type->array_v2.arrlen);
p_name = (const struct p_string*)((const unsigned char*)&type->array_v2.arrlen + leaf_len);
retv = codeview_add_type_array(module, curr_type, terminate_string(p_name),
retv = codeview_add_type_array(ctp->module, curr_type, terminate_string(p_name),
type->array_v2.elemtype, type->array_v2.idxtype, value);
break;
case LF_ARRAY_V3:
leaf_len = numeric_leaf(&value, &type->array_v3.arrlen);
c_name = (const char*)&type->array_v3.arrlen + leaf_len;
retv = codeview_add_type_array(module, curr_type, c_name,
retv = codeview_add_type_array(ctp->module, curr_type, c_name,
type->array_v3.elemtype, type->array_v3.idxtype, value);
break;
@ -842,40 +849,14 @@ static int codeview_parse_type_table(struct module* module, const BYTE* table,
type->bitfield_v2.nbits,
type->bitfield_v2.type);
break;
case LF_FIELDLIST_V1:
case LF_FIELDLIST_V2:
{
/*
* A 'field list' is a CodeView-specific data type which doesn't
* directly correspond to any high-level data type. It is used
* to hold the collection of members of a struct, class, union
* or enum type. The actual definition of that type will follow
* later, and refer to the field list definition record.
*
* As we don't have a field list type ourselves, we look ahead
* in the field list to try to find out whether this field list
* will be used for an enum or struct type, and create a dummy
* type of the corresponding sort. Later on, the definition of
* the 'real' type will copy the member / enumeration data.
*/
const unsigned char* list = type->fieldlist.list;
int len = ((const BYTE*)type + type->generic.len + 2) - list;
if (((const union codeview_fieldtype*)list)->generic.id == LF_ENUMERATE_V1 ||
((const union codeview_fieldtype*)list)->generic.id == LF_ENUMERATE_V3)
retv = codeview_add_type_enum_field_list(module, curr_type, list, len);
else
retv = codeview_add_type_struct_field_list(module, curr_type, list, len);
}
break;
case LF_STRUCTURE_V1:
case LF_CLASS_V1:
leaf_len = numeric_leaf(&value, &type->struct_v1.structlen);
p_name = (const struct p_string*)((const unsigned char*)&type->struct_v1.structlen + leaf_len);
retv = codeview_add_type_struct(module, curr_type, terminate_string(p_name),
value, type->struct_v1.fieldlist,
type_ref = codeview_jump_to_type(ctp, type->struct_v1.fieldlist);
retv = codeview_add_type_struct(ctp->module, curr_type, terminate_string(p_name),
value, type_ref,
type->generic.id == LF_CLASS_V1 ? UdtClass : UdtStruct);
break;
@ -883,9 +864,9 @@ static int codeview_parse_type_table(struct module* module, const BYTE* table,
case LF_CLASS_V2:
leaf_len = numeric_leaf(&value, &type->struct_v2.structlen);
p_name = (const struct p_string*)((const unsigned char*)&type->struct_v2.structlen + leaf_len);
retv = codeview_add_type_struct(module, curr_type, terminate_string(p_name),
value, type->struct_v2.fieldlist,
type_ref = codeview_jump_to_type(ctp, type->struct_v2.fieldlist);
retv = codeview_add_type_struct(ctp->module, curr_type, terminate_string(p_name),
value, type_ref,
type->generic.id == LF_CLASS_V2 ? UdtClass : UdtStruct);
break;
@ -893,53 +874,62 @@ static int codeview_parse_type_table(struct module* module, const BYTE* table,
case LF_CLASS_V3:
leaf_len = numeric_leaf(&value, &type->struct_v3.structlen);
c_name = (const char*)&type->struct_v3.structlen + leaf_len;
retv = codeview_add_type_struct(module, curr_type, c_name,
value, type->struct_v3.fieldlist,
type_ref = codeview_jump_to_type(ctp, type->struct_v3.fieldlist);
retv = codeview_add_type_struct(ctp->module, curr_type, c_name,
value, type_ref,
type->generic.id == LF_CLASS_V3 ? UdtClass : UdtStruct);
break;
case LF_UNION_V1:
leaf_len = numeric_leaf(&value, &type->union_v1.un_len);
p_name = (const struct p_string*)((const unsigned char*)&type->union_v1.un_len + leaf_len);
retv = codeview_add_type_struct(module, curr_type, terminate_string(p_name),
value, type->union_v1.fieldlist, UdtUnion);
type_ref = codeview_jump_to_type(ctp, type->union_v1.fieldlist);
retv = codeview_add_type_struct(ctp->module, curr_type, terminate_string(p_name),
value, type_ref, UdtUnion);
break;
case LF_UNION_V2:
leaf_len = numeric_leaf(&value, &type->union_v2.un_len);
p_name = (const struct p_string*)((const unsigned char*)&type->union_v2.un_len + leaf_len);
retv = codeview_add_type_struct(module, curr_type, terminate_string(p_name),
value, type->union_v2.fieldlist, UdtUnion);
type_ref = codeview_jump_to_type(ctp, type->union_v2.fieldlist);
retv = codeview_add_type_struct(ctp->module, curr_type, terminate_string(p_name),
value, type_ref, UdtUnion);
break;
case LF_UNION_V3:
leaf_len = numeric_leaf(&value, &type->union_v3.un_len);
c_name = (const char*)&type->union_v3.un_len + leaf_len;
retv = codeview_add_type_struct(module, curr_type, c_name,
value, type->union_v3.fieldlist, UdtUnion);
type_ref = codeview_jump_to_type(ctp, type->union_v3.fieldlist);
retv = codeview_add_type_struct(ctp->module, curr_type, c_name,
value, type_ref, UdtUnion);
break;
case LF_ENUM_V1:
retv = codeview_add_type_enum(module, curr_type, terminate_string(&type->enumeration_v1.p_name),
type->enumeration_v1.field);
type_ref = codeview_jump_to_type(ctp, type->enumeration_v1.fieldlist);
retv = codeview_add_type_enum(ctp->module, curr_type,
terminate_string(&type->enumeration_v1.p_name),
type_ref);
break;
case LF_ENUM_V2:
retv = codeview_add_type_enum(module, curr_type, terminate_string(&type->enumeration_v2.p_name),
type->enumeration_v2.field);
type_ref = codeview_jump_to_type(ctp, type->enumeration_v2.fieldlist);
retv = codeview_add_type_enum(ctp->module, curr_type,
terminate_string(&type->enumeration_v2.p_name),
type_ref);
break;
case LF_ENUM_V3:
retv = codeview_add_type_enum(module, curr_type, type->enumeration_v3.name,
type->enumeration_v3.field);
type_ref = codeview_jump_to_type(ctp, type->enumeration_v3.fieldlist);
retv = codeview_add_type_enum(ctp->module, curr_type, type->enumeration_v3.name,
type_ref);
break;
case LF_PROCEDURE_V1:
retv = codeview_new_func_signature(module, curr_type,
retv = codeview_new_func_signature(ctp->module, curr_type,
type->procedure_v1.rvtype,
type->procedure_v1.call);
break;
case LF_PROCEDURE_V2:
retv = codeview_new_func_signature(module, curr_type,
retv = codeview_new_func_signature(ctp->module, curr_type,
type->procedure_v2.rvtype,
type->procedure_v2.call);
break;
@ -947,7 +937,7 @@ static int codeview_parse_type_table(struct module* module, const BYTE* table,
/* FIXME: for C++, this is plain wrong, but as we don't use arg types
* nor class information, this would just do for now
*/
retv = codeview_new_func_signature(module, curr_type,
retv = codeview_new_func_signature(ctp->module, curr_type,
type->mfunction_v1.rvtype,
type->mfunction_v1.call);
break;
@ -955,7 +945,7 @@ static int codeview_parse_type_table(struct module* module, const BYTE* table,
/* FIXME: for C++, this is plain wrong, but as we don't use arg types
* nor class information, this would just do for now
*/
retv = codeview_new_func_signature(module, curr_type,
retv = codeview_new_func_signature(ctp->module, curr_type,
type->mfunction_v2.rvtype,
type->mfunction_v2.call);
break;
@ -1795,10 +1785,10 @@ static void pdb_process_types(const struct msc_debug_info* msc_dbg,
if (types_image)
{
PDB_TYPES types;
DWORD* offset;
DWORD num, total;
const BYTE* table;
struct codeview_type_parse ctp;
DWORD total;
const BYTE* ptr;
DWORD* offset;
pdb_convert_types_header(&types, types_image);
@ -1814,21 +1804,23 @@ static void pdb_process_types(const struct msc_debug_info* msc_dbg,
ERR("-Unknown type info version %ld\n", types.version);
}
ctp.module = msc_dbg->module;
/* reconstruct the types offset...
* FIXME: maybe it's present in the newest PDB_TYPES structures
*/
total = types.last_index - types.first_index + 1;
offset = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) * total);
table = ptr = types_image + types.type_offset;
num = 0;
while (ptr < table + types.type_size && num < total)
ctp.table = ptr = types_image + types.type_offset;
ctp.num = 0;
while (ptr < ctp.table + types.type_size && ctp.num < total)
{
offset[num++] = ptr - table;
offset[ctp.num++] = ptr - ctp.table;
ptr += ((const union codeview_type*)ptr)->generic.len + 2;
}
ctp.offset = offset;
/* Read type table */
codeview_parse_type_table(msc_dbg->module, table, offset, num);
codeview_parse_type_table(&ctp);
HeapFree(GetProcessHeap(), 0, offset);
pdb_free(types_image);
}

View File

@ -294,7 +294,7 @@ union codeview_type
short int id;
short int count;
short int type;
short int field;
short int fieldlist;
short int property;
struct p_string p_name;
} enumeration_v1;
@ -306,7 +306,7 @@ union codeview_type
short int count;
short int property;
unsigned int type;
unsigned int field;
unsigned int fieldlist;
struct p_string p_name;
} enumeration_v2;
@ -317,17 +317,10 @@ union codeview_type
short int count;
short int property;
unsigned int type;
unsigned int field;
unsigned int fieldlist;
char name[1];
} enumeration_v3;
struct
{
unsigned short int len;
short int id;
unsigned char list[1];
} fieldlist;
struct
{
unsigned short int len;
@ -379,6 +372,23 @@ union codeview_type
} mfunction_v2;
};
union codeview_reftype
{
struct
{
unsigned short int len;
short int id;
} generic;
struct
{
unsigned short int len;
short int id;
unsigned char list[1];
} fieldlist;
};
union codeview_fieldtype
{
struct