Feature #13698
CTF could handle C99 VLAs in function arguments
0%
Description
ctfconvert
cannot convert data for function definitions which contain some types of C99 variable length array (VLA) definitions.
For example:
void t(int n, int arr[n][n]) { }
build% /opt/onbld/bin/i386/ctfconvert -k VLA.o ctfconvert: CTF conversion failed: failed to get DW_FORM_block1 (10) value for DW_AT_upper_bound: DW_DLE_ATTR_FORM_BAD: In function formudata (internal function) on seeing form 0xa (DW_FORM_block1)
I've seen real world examples where the DWARF data form is DW_FORM_block1
and DW_FORM_ref4
.
The DWARF data for this example is:
< 2><0x0000004e> DW_TAG_formal_parameter DW_AT_name n DW_AT_decl_file 0x00000001 /data/omnios-build/ctf/VLA.c DW_AT_decl_line 0x00000001 DW_AT_decl_column 0x0000000c DW_AT_type <0x0000006b> DW_AT_location len 0x0002: 0x914c: DW_OP_fbreg -52 < 2><0x0000005b> DW_TAG_formal_parameter DW_AT_name arr DW_AT_decl_file 0x00000001 /data/omnios-build/ctf/VLA.c DW_AT_decl_line 0x00000001 DW_AT_decl_column 0x00000013 DW_AT_type <0x0000008c> DW_AT_location len 0x0002: 0x9140: DW_OP_fbreg -64 < 1><0x0000006b> DW_TAG_base_type DW_AT_byte_size 0x00000004 DW_AT_encoding DW_ATE_signed DW_AT_name int < 1><0x00000072> DW_TAG_array_type DW_AT_type <0x0000006b> DW_AT_sibling <0x00000085> < 2><0x0000007b> DW_TAG_subrange_type DW_AT_type <0x00000085> DW_AT_upper_bound DW_OP_fbreg -40 DW_OP_deref< 1><0x00000085> DW_TAG_base_type DW_AT_byte_size 0x00000008 DW_AT_encoding DW_ATE_unsigned DW_AT_name long unsigned int < 1><0x0000008c> DW_TAG_pointer_type DW_AT_byte_size 0x00000008 DW_AT_type <0x00000072>
It seems that we could just set the upper bound to 0 here rather than failing the entire conversion and leaving the object with no CTF at all.
Updated by Robert Mustacchi 14 days ago
Treating this as basically a zero length array like we do the arrays at the end of functions seems reasonable for CTF at this time.
Updated by Andy Fiddaman 14 days ago
- Status changed from New to In Progress
- Assignee set to Andy Fiddaman
Updated by Andy Fiddaman 5 days ago
Investigating this further since the proposed fix makes these multi-dimensional arrays look like function pointers in the C-style output.
Here is how the DWARF looks for a couple of examples:
int vla1(int n1, int arr1[n1]) < 2><0x0000010d> DW_TAG_formal_parameter DW_AT_name arr1 DW_AT_decl_file 0x00000001 .../util-tests/tests/ctf/af.c DW_AT_decl_line 0x0000001a DW_AT_decl_column 0x00000012 DW_AT_type <0x0000011d> DW_AT_location len 0x0002: 0x9160: DW_OP_fbreg -32 < 1><0x0000011d> DW_TAG_pointer_type DW_AT_byte_size 0x00000008 DW_AT_type <0x00000050> < 1><0x00000050> DW_TAG_base_type DW_AT_byte_size 0x00000004 DW_AT_encoding DW_ATE_signed DW_AT_name int
int vla2(int n2, int arr2[n2][n2]) < 2><0x000000af> DW_TAG_formal_parameter DW_AT_name arr2 DW_AT_decl_file 0x00000001 .../util-tests/tests/ctf/af.c DW_AT_decl_line 0x00000020 DW_AT_decl_column 0x00000012 DW_AT_type <0x000000d2> DW_AT_location len 0x0002: 0x9140: DW_OP_fbreg -64 < 1><0x000000bf> DW_TAG_array_type DW_AT_type <0x00000050> DW_AT_sibling <0x000000d2> < 2><0x000000c8> DW_TAG_subrange_type DW_AT_type <0x0000002d> DW_AT_upper_bound DW_OP_fbreg -40 DW_OP_deref< 1><0x000000d2> DW_TAG_pointer_type DW_AT_byte_size 0x00000008 DW_AT_type <0x000000bf>
with the following generated CTF data
- Functions --------------------------------------------------------------------- [0] vla1 (8) returns: 1 args: (1, 5) [1] vla2 (9) returns: 1 args: (1, 4) - Types ------------------------------------------------------------------------- <1> int encoding=SIGNED offset=0 bits=32 [2] long encoding=SIGNED offset=0 bits=64 [3] int [0] contents: 1, index: 2 <4> int (*)[0] refers to 3 <5> int * refers to 1
Updated by Robert Mustacchi 3 days ago
It looks like the secret here is this block comment in ctf_type_qlname:
/* * If the type graph's order conflicts with lexical precedence order * for pointers or arrays, then we need to surround the declarations at * the corresponding lexical precedence with parentheses. This can * result in either a parenthesized pointer (*) as in int (*)() or * int (*)[], or in a parenthesized pointer and array as in int (*[])(). */
So that's where this is coming in from and while it looks like a function pointer, it is in fact not.