[Lldb-commits] [lldb] r246955 - Bug 24457 - X87 FPU Special Purpose Registers
Pavel Labath via lldb-commits
lldb-commits at lists.llvm.org
Mon Sep 7 01:58:25 PDT 2015
Hi,
this new test fails when the inferior is compiled with clang, as the
produced line tables are not what you expect. I have marked it as
XFAIL to get the bots green, but it would be great if we could write
it in a way that works on clang as well.
pl
On 7 September 2015 at 08:40, Abhishek Aggarwal via lldb-commits
<lldb-commits at lists.llvm.org> wrote:
> Author: abhishek
> Date: Mon Sep 7 02:40:16 2015
> New Revision: 246955
>
> URL: http://llvm.org/viewvc/llvm-project?rev=246955&view=rev
> Log:
> Bug 24457 - X87 FPU Special Purpose Registers
>
> Summary:
> - For 'register read --all' command on x86_64-Linux Platform:
>
> -- Provide correct values of X87 FPU Special Purpose Registers
> -- Both 32-bit & 64-bit inferiors give correct values on this
> Platform
>
> - Added a Test Vector:
> -- To verify the expected behaviour of the command
>
> Signed-off-by: Abhishek Aggarwal <abhishek.a.aggarwal at intel.com>
>
> Reviewers: ashok.thirumurthi, granata.enrico, tfiala, clayborg
>
> Differential Revision: http://reviews.llvm.org/D12592
>
> Added:
> lldb/trunk/test/functionalities/register/a.cpp (with props)
> Modified:
> lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp (contents, props changed)
> lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
> lldb/trunk/test/functionalities/register/Makefile (contents, props changed)
> lldb/trunk/test/functionalities/register/TestRegisters.py (contents, props changed)
> lldb/trunk/test/functionalities/register/main.cpp (contents, props changed)
>
> Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp?rev=246955&r1=246954&r2=246955&view=diff
> ==============================================================================
> --- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp (original)
> +++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp Mon Sep 7 02:40:16 2015
> @@ -422,6 +422,10 @@ NativeRegisterContextLinux_x86_64::Nativ
>
> // Clear out the FPR state.
> ::memset(&m_fpr, 0, sizeof(FPR));
> +
> + // Store byte offset of fctrl (i.e. first register of FPR)
> + const RegisterInfo *reg_info_fctrl = GetRegisterInfoByName("fctrl");
> + m_fctrl_offset_in_userarea = reg_info_fctrl->byte_offset;
> }
>
> // CONSIDER after local and llgs debugging are merged, register set support can
> @@ -559,8 +563,16 @@ NativeRegisterContextLinux_x86_64::ReadR
> }
>
> // Get pointer to m_fpr.xstate.fxsave variable and set the data from it.
> - assert (reg_info->byte_offset < sizeof(m_fpr));
> - uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset;
> +
> + // Byte offsets of all registers are calculated wrt 'UserArea' structure.
> + // However, ReadFPR() reads fpu registers {using ptrace(PTRACE_GETFPREGS,..)}
> + // and stores them in 'm_fpr' (of type FPR structure). To extract values of fpu
> + // registers, m_fpr should be read at byte offsets calculated wrt to FPR structure.
> +
> + // Since, FPR structure is also one of the member of UserArea structure.
> + // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - byte_offset(fctrl wrt UserArea)
> + assert ( (reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr));
> + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea;
> switch (reg_info->byte_size)
> {
> case 2:
> @@ -620,8 +632,16 @@ NativeRegisterContextLinux_x86_64::Write
> else
> {
> // Get pointer to m_fpr.xstate.fxsave variable and set the data to it.
> - assert (reg_info->byte_offset < sizeof(m_fpr));
> - uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset;
> +
> + // Byte offsets of all registers are calculated wrt 'UserArea' structure.
> + // However, WriteFPR() takes m_fpr (of type FPR structure) and writes only fpu
> + // registers using ptrace(PTRACE_SETFPREGS,..) API. Hence fpu registers should
> + // be written in m_fpr at byte offsets calculated wrt FPR structure.
> +
> + // Since, FPR structure is also one of the member of UserArea structure.
> + // byte_offset(fpu wrt FPR) = byte_offset(fpu wrt UserArea) - byte_offset(fctrl wrt UserArea)
> + assert ( (reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(m_fpr));
> + uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset - m_fctrl_offset_in_userarea;
> switch (reg_info->byte_size)
> {
> case 2:
>
> Propchange: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
> ------------------------------------------------------------------------------
> svn:executable = *
>
> Modified: lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h?rev=246955&r1=246954&r2=246955&view=diff
> ==============================================================================
> --- lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h (original)
> +++ lldb/trunk/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h Mon Sep 7 02:40:16 2015
> @@ -136,6 +136,7 @@ namespace process_linux {
> YMM m_ymm_set;
> RegInfo m_reg_info;
> uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64];
> + uint32_t m_fctrl_offset_in_userarea;
>
> // Private member methods.
> bool IsRegisterSetAvailable (uint32_t set_index) const;
>
> Modified: lldb/trunk/test/functionalities/register/Makefile
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/register/Makefile?rev=246955&r1=246954&r2=246955&view=diff
> ==============================================================================
> --- lldb/trunk/test/functionalities/register/Makefile (original)
> +++ lldb/trunk/test/functionalities/register/Makefile Mon Sep 7 02:40:16 2015
> @@ -1,5 +1,5 @@
> LEVEL = ../../make
>
> -CXX_SOURCES := main.cpp
> +CXX_SOURCES := main.cpp a.cpp
>
> include $(LEVEL)/Makefile.rules
>
> Propchange: lldb/trunk/test/functionalities/register/Makefile
> ------------------------------------------------------------------------------
> svn:executable = *
>
> Modified: lldb/trunk/test/functionalities/register/TestRegisters.py
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/register/TestRegisters.py?rev=246955&r1=246954&r2=246955&view=diff
> ==============================================================================
> --- lldb/trunk/test/functionalities/register/TestRegisters.py (original)
> +++ lldb/trunk/test/functionalities/register/TestRegisters.py Mon Sep 7 02:40:16 2015
> @@ -35,6 +35,13 @@ class RegisterCommandsTestCase(TestBase)
> self.buildDefault()
> self.fp_register_write()
>
> + def test_fp_special_purpose_register_read(self):
> + """Test commands that read fpu special purpose registers."""
> + if not self.getArchitecture() in ['amd64', 'i386', 'x86_64']:
> + self.skipTest("This test requires x86 or x86_64 as the architecture for the inferior")
> + self.buildDefault()
> + self.fp_special_purpose_register_read()
> +
> def test_register_expressions(self):
> """Test expression evaluation with commands related to registers."""
> if not self.getArchitecture() in ['amd64', 'i386', 'x86_64']:
> @@ -152,6 +159,69 @@ class RegisterCommandsTestCase(TestBase)
> self.expect("register read " + register,
> substrs = [register + ' = ', new_value])
>
> + def fp_special_purpose_register_read(self):
> + exe = os.path.join(os.getcwd(), "a.out")
> +
> + # Create a target by the debugger.
> + target = self.dbg.CreateTarget(exe)
> + self.assertTrue(target, VALID_TARGET)
> +
> + # Find the line number to break inside a.cpp.
> + self.line = line_number('a.cpp', '// Set break point at this line.')
> +
> + # Set breakpoint
> + lldbutil.run_break_set_by_file_and_line (self, "a.cpp", self.line, num_expected_locations=1, loc_exact=True)
> +
> + # Launch the process, and do not stop at the entry point.
> + self.runCmd ("run", RUN_SUCCEEDED)
> +
> + process = target.GetProcess()
> + self.assertTrue(process.GetState() == lldb.eStateStopped,
> + PROCESS_STOPPED)
> +
> + thread = process.GetThreadAtIndex(0)
> + self.assertTrue(thread.IsValid(), "current thread is valid")
> +
> + currentFrame = thread.GetFrameAtIndex(0)
> + self.assertTrue(currentFrame.IsValid(), "current frame is valid")
> +
> + # Extract the value of fstat and ftag flag at the point just before
> + # we start pushing floating point values on st% register stack
> + value = currentFrame.FindValue("fstat", lldb.eValueTypeRegister)
> + error = lldb.SBError()
> + reg_value_fstat_initial = value.GetValueAsUnsigned(error, 0)
> +
> + self.assertTrue(error.Success(), "reading a value for fstat")
> + value = currentFrame.FindValue("ftag", lldb.eValueTypeRegister)
> + error = lldb.SBError()
> + reg_value_ftag_initial = value.GetValueAsUnsigned(error, 0)
> +
> + self.assertTrue(error.Success(), "reading a value for ftag")
> + fstat_top_pointer_initial = (reg_value_fstat_initial & 0x3800)>>11
> +
> + # Execute 'si' aka 'thread step-inst' instruction 5 times and with
> + # every execution verify the value of fstat and ftag registers
> + for x in range(0,5):
> + # step into the next instruction to push a value on 'st' register stack
> + self.runCmd ("si", RUN_SUCCEEDED)
> +
> + # Verify fstat and save it to be used for verification in next execution of 'si' command
> + if not (reg_value_fstat_initial & 0x3800):
> + self.expect("register read fstat",
> + substrs = ['fstat' + ' = ', str("0x%0.4x" %((reg_value_fstat_initial & ~(0x3800))| 0x3800))])
> + reg_value_fstat_initial = ((reg_value_fstat_initial & ~(0x3800))| 0x3800)
> + fstat_top_pointer_initial = 7
> + else :
> + self.expect("register read fstat",
> + substrs = ['fstat' + ' = ', str("0x%0.4x" % (reg_value_fstat_initial - 0x0800))])
> + reg_value_fstat_initial = (reg_value_fstat_initial - 0x0800)
> + fstat_top_pointer_initial -= 1
> +
> + # Verify ftag and save it to be used for verification in next execution of 'si' command
> + self.expect("register read ftag",
> + substrs = ['ftag' + ' = ', str("0x%0.4x" % (reg_value_ftag_initial | (1<< fstat_top_pointer_initial)))])
> + reg_value_ftag_initial = reg_value_ftag_initial | (1<< fstat_top_pointer_initial)
> +
> def fp_register_write(self):
> exe = os.path.join(os.getcwd(), "a.out")
>
>
> Propchange: lldb/trunk/test/functionalities/register/TestRegisters.py
> ------------------------------------------------------------------------------
> svn:executable = *
>
> Added: lldb/trunk/test/functionalities/register/a.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/register/a.cpp?rev=246955&view=auto
> ==============================================================================
> --- lldb/trunk/test/functionalities/register/a.cpp (added)
> +++ lldb/trunk/test/functionalities/register/a.cpp Mon Sep 7 02:40:16 2015
> @@ -0,0 +1,40 @@
> +//===-- a.cpp ------------------------------------------------*- C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +#include <stdio.h>
> +
> +long double
> +return_long_double (long double value)
> +{
> + float a=2, b=4,c=8, d=16, e=32, f=64, k=128, l=256, add=0;
> +__asm__ ( "fld %1 ;"
> + "fld %2 ;"
> + "fld %3 ;"
> + "fld %4 ;"
> + "fld %5 ;"
> + "fld %6 ;"
> + "fld %7 ;"
> + "fadd ;" : "=g" (add) : "g" (a), "g" (b), "g" (c), "g" (d), "g" (e), "g" (f), "g" (k), "g" (l) ); // Set break point at this line.
> + return value;
> +}
> +
> +long double
> +outer_return_long_double (long double value)
> +{
> + long double val = return_long_double(value);
> + val *= 2 ;
> + return val;
> +}
> +
> +long double
> +outermost_return_long_double (long double value)
> +{
> + long double val = outer_return_long_double(value);
> + val *= 2 ;
> + return val;
> +}
>
> Propchange: lldb/trunk/test/functionalities/register/a.cpp
> ------------------------------------------------------------------------------
> svn:executable = *
>
> Modified: lldb/trunk/test/functionalities/register/main.cpp
> URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/register/main.cpp?rev=246955&r1=246954&r2=246955&view=diff
> ==============================================================================
> --- lldb/trunk/test/functionalities/register/main.cpp (original)
> +++ lldb/trunk/test/functionalities/register/main.cpp Mon Sep 7 02:40:16 2015
> @@ -15,6 +15,8 @@
> #include <chrono>
> #include <thread>
>
> +long double outermost_return_long_double (long double my_long_double);
> +
> int main (int argc, char const *argv[])
> {
> #if defined(__linux__)
> @@ -32,6 +34,7 @@ int main (int argc, char const *argv[])
>
> char my_string[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 0};
> double my_double = 1234.5678;
> + long double my_long_double = 1234.5678;
>
> // For simplicity assume that any cmdline argument means wait for attach.
> if (argc > 1)
> @@ -43,5 +46,6 @@ int main (int argc, char const *argv[])
>
> printf("my_string=%s\n", my_string);
> printf("my_double=%g\n", my_double);
> + outermost_return_long_double (my_long_double);
> return 0;
> }
>
> Propchange: lldb/trunk/test/functionalities/register/main.cpp
> ------------------------------------------------------------------------------
> svn:executable = *
>
>
> _______________________________________________
> lldb-commits mailing list
> lldb-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
More information about the lldb-commits
mailing list