[Bug tdep/25096] amd64_push_arguments places values in wrong register

cvs-commit at gcc dot gnu.org sourceware-bugzilla@sourceware.org
Wed Oct 16 15:12:00 GMT 2019


https://sourceware.org/bugzilla/show_bug.cgi?id=25096

--- Comment #6 from cvs-commit at gcc dot gnu.org <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Tom de Vries <vries@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=745ff14e6e1b88f04eb447d4883fab81650f745f

commit 745ff14e6e1b88f04eb447d4883fab81650f745f
Author: Tom de Vries <tdevries@suse.de>
Date:   Wed Oct 16 17:11:56 2019 +0200

    [gdb/tdep] Fix 'Unexpected register class' assert in amd64_push_arguments

    Atm, when executing gdb.base/infcall-nested-structs.exp on x86_64-linux, we
get:
    ...
    FAIL: gdb.base/infcall-nested-structs.exp: l=c++: types-tc-tf: \
      p/d check_arg_struct_02_01 (ref_val_struct_02_01)
    FAIL: gdb.base/infcall-nested-structs.exp: l=c++: types-ts-tf: \
      p/d check_arg_struct_02_01 (ref_val_struct_02_01)
    FAIL: gdb.base/infcall-nested-structs.exp: l=c++: types-ti-tf: \
      p/d check_arg_struct_02_01 (ref_val_struct_02_01)

                    === gdb Summary ===

    nr of expected passes            9255
    nr of unexpected failures        3
    nr of expected failures          142
    ...

    The 3 FAILs are reported as PR tdep/25096.

    The 142 XFAILs are for a gdb assertion failure, reported in PR tdep/24104,
    which should have been KFAILs since there's a problem in gdb rather than in
    the environment.

    A minimal version of the assertion failure looks like this. Consider
test.c:
    ...
    struct s { struct { } es1; long f; };
    struct s ref = { {}, 'f' };

    int __attribute__((noinline,noclone)) check (struct s arg)
    { return arg.f == 'f'; }

    int main (void)
    { return check (ref); }
    ...

    When calling 'check (ref)' from main, we have '1' as expected:
    ...
    $ g++ test3.c -g && ( ./a.out; echo $? )
    1
    ...

    But when calling 'check (ref)' from the gdb prompt, we get:
    ...
    $ gdb a.out -batch -ex start -ex "p check (ref)"
    Temporary breakpoint 1 at 0x4004f7: file test.c, line 8.

    Temporary breakpoint 1, main () at test.c:8
    8       { return check (ref); }
    src/gdb/amd64-tdep.c:982: internal-error: \
      CORE_ADDR amd64_push_arguments(regcache*, int, value**, CORE_ADDR, \
                                     function_call_return_method): \
      Assertion `!"Unexpected register class."' failed.
    ...

    The assert happens in this loop in amd64_push_arguments:
    ...
              for (j = 0; len > 0; j++, len -= 8)
                {
                  int regnum = -1;
                  int offset = 0;

                  switch (theclass[j])
                    {
                    case AMD64_INTEGER:
                      regnum = integer_regnum[integer_reg++];
                      break;

                    case AMD64_SSE:
                      regnum = sse_regnum[sse_reg++];
                      break;

                    case AMD64_SSEUP:
                      gdb_assert (sse_reg > 0);
                      regnum = sse_regnum[sse_reg - 1];
                      offset = 8;
                      break;

                    default:
                      gdb_assert (!"Unexpected register class.");
                    }
                ...
                }
    ...
    when processing theclass[0], which is AMD64_NO_CLASS:
    ...
    (gdb) p theclass
    $1 = {AMD64_NO_CLASS, AMD64_INTEGER}
    ...

    The layout of struct s is that the empty field es1 occupies one byte (due
to
    c++) at offset 0, and the long field f occupies 8 bytes at offset 8.

    When compiling at -O2, we can see from the disassembly of main:
    ...
      4003f0:       48 8b 3d 41 0c 20 00    mov    0x200c41(%rip),%rdi \
                                                   # 601038 <ref+0x8>
      4003f7:       e9 e4 00 00 00          jmpq   4004e0 <_Z5check1s>
      4003fc:       0f 1f 40 00             nopl   0x0(%rax)
    ...
    that check is called with field f passed in %rdi, meaning that the
    classification in theclass is correct, it's just not supported in the loop
in
    amd64_push_arguments mentioned above.

    Fix the assert by implementing support for 'AMD64_NO_CLASS' in that loop.

    This exposes 9 more FAILs of the PR tdep/25096 type, so mark all 12 of them
as
    KFAIL.

    Tested on x86_64-linux.

    Tested with g++ 4.8.5, 7.4.1, 8.3.1, 9.2.1.  With 4.8.5, 3 of the 12 KFAILs
    are KPASSing.

    Tested with clang++ 5.0.2 (which requires removing
additional_flags=-Wno-psabi
    and adding additional_flags=-Wno-deprecated).

    gdb/ChangeLog:

    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'.

    gdb/testsuite/ChangeLog:

    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.

    Change-Id: I8b66345bbf5c00209ca75b1209fd4d60b36e9ede

-- 
You are receiving this mail because:
You are on the CC list for the bug.


More information about the Gdb-prs mailing list