Fix linux x86 debugging on a linux x86 host (32-bit on 32-bit).

This change fixes up issues with specifying the size of the i386
register infos for FPU registers.  The bug was that for the i386
register context, the size of the FPU registers were still being
computed based on the x86_64 FXSAVE structure.

This change permits the FPR_SIZE macro to optionally be defined
outside of RegisterInfos_i386.h, which RegisterContextLinux_i386.cpp
does properly. It redefines the FPR_i386 structure with all the
accessible parts that RegisterInfos_i386.h wants to see, which we had
not done before when we made the overall size of the structure
properly sized a recently.

This change also modifies POSIXThread to create a
RegisterContextLinux_i386 only when the host is 32-bit; otherwise, it
uses the RegisterContextLinux_x86_64, which works properly for 32-bit
and 64-bit inferiors on a 64-bit host.

I tested this debugging a Linux x86 exe on an x86 host (Ubuntu 13.10
x86), and debugging a Linux x86 exe and a Linux x86-64 exe on an
x86-64 host (Ubuntu 12.04 LTS).  Those cases all worked.

Thanks to Matthew Gardiner who discoverd may key insights into
tracking down the issue. The motivation for this change and some of
the code originates from him via this thread:

http://lists.cs.uiuc.edu/pipermail/lldb-commits/Week-of-Mon-20140224/010554.html

llvm-svn: 202428
This commit is contained in:
Todd Fiala 2014-02-27 20:46:12 +00:00
parent 95833f33bd
commit 4507f06aaa
4 changed files with 40 additions and 11 deletions

View File

@ -168,9 +168,9 @@ PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size
errno = 0; errno = 0;
if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET) if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET)
result = ptrace(static_cast<__ptrace_request>(req), pid, *(unsigned int *)addr, data); result = ptrace(static_cast<__ptrace_request>(req), static_cast<pid_t>(pid), *(unsigned int *)addr, data);
else else
result = ptrace(static_cast<__ptrace_request>(req), pid, addr, data); result = ptrace(static_cast<__ptrace_request>(req), static_cast<pid_t>(pid), addr, data);
if (log) if (log)
log->Printf("ptrace(%s, %" PRIu64 ", %p, %p, %zu)=%lX called from file %s line %d", log->Printf("ptrace(%s, %" PRIu64 ", %p, %p, %zu)=%lX called from file %s line %d",

View File

@ -190,7 +190,17 @@ POSIXThread::GetRegisterContext()
reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); reg_interface = new RegisterContextFreeBSD_x86_64(target_arch);
break; break;
case llvm::Triple::Linux: case llvm::Triple::Linux:
reg_interface = new RegisterContextLinux_x86_64(target_arch); if (Host::GetArchitecture().GetAddressByteSize() == 4)
{
// 32-bit hosts run with a RegisterContextLinux_i386 context.
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_i386(target_arch));
}
else
{
assert((Host::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host");
// X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context.
reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_x86_64(target_arch));
}
break; break;
default: default:
assert(false && "OS not supported"); assert(false && "OS not supported");

View File

@ -36,14 +36,30 @@ struct GPR
struct FPR_i386 struct FPR_i386
{ {
int32_t cwd; uint16_t fctrl; // FPU Control Word (fcw)
int32_t swd; uint16_t fstat; // FPU Status Word (fsw)
int32_t twd; uint16_t ftag; // FPU Tag Word (ftw)
int32_t fip; uint16_t fop; // Last Instruction Opcode (fop)
int32_t fcs; union
int32_t foo; {
int32_t fos; struct
int32_t st_space [20]; {
uint64_t fip; // Instruction Pointer
uint64_t fdp; // Data Pointer
} x86_64;
struct
{
uint32_t fioff; // FPU IP Offset (fip)
uint32_t fiseg; // FPU IP Selector (fcs)
uint32_t fooff; // FPU Operand Pointer Offset (foo)
uint32_t foseg; // FPU Operand Pointer Selector (fos)
} i386;
} ptr;
uint32_t mxcsr; // MXCSR Register State
uint32_t mxcsrmask; // MXCSR Mask
MMSReg stmm[8]; // 8*16 bytes for each FP-reg = 128 bytes
XMMReg xmm[8]; // 8*16 bytes for each XMM-reg = 128 bytes
uint32_t padding[56];
}; };
struct UserArea struct UserArea
@ -69,6 +85,7 @@ struct UserArea
#define DR_SIZE sizeof(UserArea::u_debugreg[0]) #define DR_SIZE sizeof(UserArea::u_debugreg[0])
#define DR_OFFSET(reg_index) \ #define DR_OFFSET(reg_index) \
(LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index])) (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index]))
#define FPR_SIZE(reg) sizeof(((FPR_i386*)NULL)->reg)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Include RegisterInfos_i386 to declare our g_register_infos_i386 structure. // Include RegisterInfos_i386 to declare our g_register_infos_i386 structure.

View File

@ -24,7 +24,9 @@
(LLVM_EXTENSION offsetof(YMM, regname)) (LLVM_EXTENSION offsetof(YMM, regname))
// Number of bytes needed to represent a FPR. // Number of bytes needed to represent a FPR.
#if !defined(FPR_SIZE)
#define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg) #define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg)
#endif
// Number of bytes needed to represent the i'th FP register. // Number of bytes needed to represent the i'th FP register.
#define FP_SIZE sizeof(((MMSReg*)NULL)->bytes) #define FP_SIZE sizeof(((MMSReg*)NULL)->bytes)