Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 02 Oct 2020 06:44:35 +0000
From:      bugzilla-noreply@freebsd.org
To:        bugs@FreeBSD.org
Subject:   [Bug 250043] ptrace() GETFPREGS/SETFPREGS uses 32-bit version of *XSAVE*/*XRSTOR* truncating FIP/FDP
Message-ID:  <bug-250043-227@https.bugs.freebsd.org/bugzilla/>

index | next in thread | raw e-mail

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=250043

            Bug ID: 250043
           Summary: ptrace() GETFPREGS/SETFPREGS uses 32-bit version of
                    *XSAVE*/*XRSTOR* truncating FIP/FDP
           Product: Base System
           Version: Unspecified
          Hardware: amd64
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: mgorny@gentoo.org
                CC: emaste@freebsd.org

This is a problem discovered while working on new FreeBSD plugin for LLDB, as
contracted to Moritz Systems by FreeBSD Foundation.

TL;DR: We'd need to replace 'plain' *xsave* and *xrstor* calls used to populate
GETFPREGS/SETFPREGS on amd64 (or possibly all of them) with *xsave*64 and
*xrstor*64.  This changes the FIP/FDP representation inside the struct not to
be truncated to 32 bits (without changing anything else).


Long version:

The fxsave, xsave... and fxrstor, xrstor... instructions have two variants on
amd64.  The variant without prefix uses a 32-bit compatible x87 register dump
structure while the variant prefixed by rex.w=1 uses a 64-bit x87 register
dump.  The latter can be done in gas by appending '64' suffix to the command,
e.g. fxsave64.

The only difference in these two variants is how FIP/FDP registers are written.
 In the 32-bit compatible variant, they are written as a 16-bit segment
register (FCS/FDS) and an actual pointer truncated to 32 bits (FIP[31:0],
FDP[31:0]), plus 16 bits of padding.  In the 64-bit version, they are written
as full 64-bit register instead.

FreeBSD currently calls the 32-bit compatible variant of instructions.  This is
problematic because it means that pointers exceeding 2^32 are truncated. 
Switching to the 64-bit variant would solve that.

This is a potentially breaking change but we don't think it is likely to break
anything.  The FIP/FDP registers are used to locate instruction and its memory
operand (if any) when software handling of x87 exceptions is used.  We don't
think modern debuggers are used often in that context and even if they are, the
current state is broken as they get a truncated pointer.

We'd lose access to respective segment registers but unless I'm mistaken they
aren't really used much these days.

The problem also affects current versions of gdb.  Linux gdb and lldb are using
the 64-bit variant.  Although it is displayed split as fiseg/fioff,
foseg/fooff, the *seg register does not contain the 16-bit segment but instead
FIP[63:32], FDP[63:32].

-- 
You are receiving this mail because:
You are the assignee for the bug.

help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-250043-227>