diff options
-rw-r--r-- | gdb/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/amd64-tdep.c | 114 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/infcall-nested-structs.exp | 8 |
4 files changed, 80 insertions, 55 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index eeba0ee..8748257 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,13 @@ 2019-10-16 Tom de Vries <tdevries@suse.de> + PR tdep/25096 + * amd64-tdep.c (amd64_classify_aggregate_field): Factor out of ... + (amd64_classify_aggregate): ... here. + (amd64_classify_aggregate_field): Handled fiels of nested structs + recursively. + +2019-10-16 Tom de Vries <tdevries@suse.de> + PR tdep/24104 * amd64-tdep.c (amd64_push_arguments): Handle AMD64_NO_CLASS in loop that handles 'theclass'. diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index 9006ec0..67a4d3f 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -579,6 +579,72 @@ amd64_has_unaligned_fields (struct type *type) return false; } +/* Classify field I of TYPE starting at BITOFFSET according to the rules for + structures and union types, and store the result in THECLASS. */ + +static void +amd64_classify_aggregate_field (struct type *type, int i, + enum amd64_reg_class theclass[2], + unsigned int bitoffset) +{ + struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i)); + int bitpos = bitoffset + TYPE_FIELD_BITPOS (type, i); + int pos = bitpos / 64; + enum amd64_reg_class subclass[2]; + int bitsize = TYPE_FIELD_BITSIZE (type, i); + int endpos; + + if (bitsize == 0) + bitsize = TYPE_LENGTH (subtype) * 8; + endpos = (bitpos + bitsize - 1) / 64; + + /* Ignore static fields, or empty fields, for example nested + empty structures.*/ + if (field_is_static (&TYPE_FIELD (type, i)) || bitsize == 0) + return; + + if (TYPE_CODE (subtype) == TYPE_CODE_STRUCT + || TYPE_CODE (subtype) == TYPE_CODE_UNION) + { + /* Each field of an object is classified recursively. */ + int j; + for (j = 0; j < TYPE_NFIELDS (subtype); j++) + amd64_classify_aggregate_field (subtype, j, theclass, bitpos); + return; + } + + gdb_assert (pos == 0 || pos == 1); + + amd64_classify (subtype, subclass); + theclass[pos] = amd64_merge_classes (theclass[pos], subclass[0]); + if (bitsize <= 64 && pos == 0 && endpos == 1) + /* This is a bit of an odd case: We have a field that would + normally fit in one of the two eightbytes, except that + it is placed in a way that this field straddles them. + This has been seen with a structure containing an array. + + The ABI is a bit unclear in this case, but we assume that + this field's class (stored in subclass[0]) must also be merged + into class[1]. In other words, our field has a piece stored + in the second eight-byte, and thus its class applies to + the second eight-byte as well. + + In the case where the field length exceeds 8 bytes, + it should not be necessary to merge the field class + into class[1]. As LEN > 8, subclass[1] is necessarily + different from AMD64_NO_CLASS. If subclass[1] is equal + to subclass[0], then the normal class[1]/subclass[1] + merging will take care of everything. For subclass[1] + to be different from subclass[0], I can only see the case + where we have a SSE/SSEUP or X87/X87UP pair, which both + use up all 16 bytes of the aggregate, and are already + handled just fine (because each portion sits on its own + 8-byte). */ + theclass[1] = amd64_merge_classes (theclass[1], subclass[0]); + if (pos == 0) + theclass[1] = amd64_merge_classes (theclass[1], subclass[1]); +} + /* Classify TYPE according to the rules for aggregate (structures and arrays) and union types, and store the result in CLASS. */ @@ -619,53 +685,7 @@ amd64_classify_aggregate (struct type *type, enum amd64_reg_class theclass[2]) || TYPE_CODE (type) == TYPE_CODE_UNION); for (i = 0; i < TYPE_NFIELDS (type); i++) - { - struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i)); - int pos = TYPE_FIELD_BITPOS (type, i) / 64; - enum amd64_reg_class subclass[2]; - int bitsize = TYPE_FIELD_BITSIZE (type, i); - int endpos; - - if (bitsize == 0) - bitsize = TYPE_LENGTH (subtype) * 8; - endpos = (TYPE_FIELD_BITPOS (type, i) + bitsize - 1) / 64; - - /* Ignore static fields, or empty fields, for example nested - empty structures.*/ - if (field_is_static (&TYPE_FIELD (type, i)) || bitsize == 0) - continue; - - gdb_assert (pos == 0 || pos == 1); - - amd64_classify (subtype, subclass); - theclass[pos] = amd64_merge_classes (theclass[pos], subclass[0]); - if (bitsize <= 64 && pos == 0 && endpos == 1) - /* This is a bit of an odd case: We have a field that would - normally fit in one of the two eightbytes, except that - it is placed in a way that this field straddles them. - This has been seen with a structure containing an array. - - The ABI is a bit unclear in this case, but we assume that - this field's class (stored in subclass[0]) must also be merged - into class[1]. In other words, our field has a piece stored - in the second eight-byte, and thus its class applies to - the second eight-byte as well. - - In the case where the field length exceeds 8 bytes, - it should not be necessary to merge the field class - into class[1]. As LEN > 8, subclass[1] is necessarily - different from AMD64_NO_CLASS. If subclass[1] is equal - to subclass[0], then the normal class[1]/subclass[1] - merging will take care of everything. For subclass[1] - to be different from subclass[0], I can only see the case - where we have a SSE/SSEUP or X87/X87UP pair, which both - use up all 16 bytes of the aggregate, and are already - handled just fine (because each portion sits on its own - 8-byte). */ - theclass[1] = amd64_merge_classes (theclass[1], subclass[0]); - if (pos == 0) - theclass[1] = amd64_merge_classes (theclass[1], subclass[1]); - } + amd64_classify_aggregate_field (type, i, theclass, 0); } /* 4. Then a post merger cleanup is done: */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 3277ee3..befc4bb 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2019-10-16 Tom de Vries <tdevries@suse.de> + PR tdep/25096 + * gdb.base/infcall-nested-structs.exp: Remove PR25096 KFAILs. + +2019-10-16 Tom de Vries <tdevries@suse.de> + PR tdep/24104 * gdb.base/infcall-nested-structs.exp: Remove XFAIL for PR tdep/24104. Add KFAIL for PR tdep/25096. diff --git a/gdb/testsuite/gdb.base/infcall-nested-structs.exp b/gdb/testsuite/gdb.base/infcall-nested-structs.exp index 957eb31..982149f 100644 --- a/gdb/testsuite/gdb.base/infcall-nested-structs.exp +++ b/gdb/testsuite/gdb.base/infcall-nested-structs.exp @@ -132,10 +132,6 @@ proc run_tests { lang types } { continue } - if { $lang == "c++" && $name == "struct_02_01" - && [regexp "^types-(tf-t(c|s|i)|t(c|s|i)-tf)" $types match] } { - setup_kfail gdb/25096 "x86_64-*-linux*" - } gdb_test "p/d check_arg_${name} (ref_val_${name})" "= 1" set refval [ get_valueof "" "ref_val_${name}" "" ] @@ -147,10 +143,6 @@ proc run_tests { lang types } { set answer [ get_valueof "" "rtn_str_${name} ()" "XXXX"] verbose -log "Answer: ${answer}" - if { $lang == "c++" && $name == "struct_02_01" - && [regexp "^types-(tf-t(c|s|i)|t(c|s|i)-tf)" $types match] } { - setup_kfail gdb/25096 "x86_64-*-linux*" - } gdb_assert [string eq ${answer} ${refval}] ${test} } else { unresolved $test |