From gclayton at apple.com Mon Feb 28 13:30:48 2011 From: gclayton at apple.com (Greg Clayton) Date: Mon, 28 Feb 2011 11:30:48 -0800 Subject: [Lldb-commits] x86_32 linux support In-Reply-To: <20110226215800.GA17824@fibrous.localdomain> References: <20110226002555.GA11412@fibrous.localdomain> <20110226215800.GA17824@fibrous.localdomain> Message-ID: <306AEF9B-A50B-4464-BE32-1FAC51DBAB4A@apple.com> On Feb 26, 2011, at 1:58 PM, Stephen Wilson wrote: > Marco, Greg, > > On Sat, Feb 26, 2011 at 03:09:45PM +0100, Marco Minutoli wrote: >> Here is the patch with the changes you have requested. > > Nice. This looks good. > > > Greg, mind if I commit this one? There is one trivial tweak needed to > avoid a compile time warning. I am happy with letting you OK the any linux specific patches. If it touches anyting in the core that is significant, then let me know, else I will let you OK the linux patches, is that alright? > >> Sorry for the duplicated header here It was late night(or maybe early >> in the morning :D) when I sent the patch to the ML. Next time I'll be >> more careful. > > No worries! We still have a bit of work to do to support i386 on linux > but this is a significant step forward. Thanks so much! > > >> Best regards, >> Marco >> >> On Sat, Feb 26, 2011 at 1:25 AM, Stephen Wilson wrote: >>> On Fri, Feb 25, 2011 at 02:52:51AM +0100, Marco Minutoli wrote: >>>> Hi everybody, >>>> >>>> as suggested by Stephen I had a look at the user_32.h Linux header and >>>> I fixed the UserArea structure. >>>> >>>> In the attachment the revised patch. As ever comments and suggestions >>>> are welcome :). >>> >>> This looks good. Only two small issues: the patch for >>> RegisterContextLinux_i386.h contains the old and new versions of your >>> patch (the latter is protected behind an #ifndef). Also, I think we >>> need the following patch for LinuxThread.cpp: Use a register context >>> according to the host instead of the process target so we can debug and >>> test lldb using 32-bit binaries on 64-bit systems. >>> >>> I have not been able to test your patch much yet -- another issue has >>> crept into the linux builds that I need to track down first... but with >>> those changes I think the patches can go in. >>> >>> >>> >>> Thanks again! >>> >>> >>> diff --git a/source/Plugins/Process/Linux/LinuxThread.cpp b/source/Plugins/Process/Linux/LinuxThread.cpp >>> index 397d31b..15bc9e3 100644 >>> --- a/source/Plugins/Process/Linux/LinuxThread.cpp >>> +++ b/source/Plugins/Process/Linux/LinuxThread.cpp >>> @@ -12,6 +12,7 @@ >>> >>> // C++ Includes >>> // Other libraries and framework includes >>> +#include "lldb/Host/Host.h" >>> #include "lldb/Target/Process.h" >>> #include "lldb/Target/StopInfo.h" >>> #include "lldb/Target/Target.h" >>> @@ -19,6 +20,7 @@ >>> #include "LinuxThread.h" >>> #include "ProcessLinux.h" >>> #include "ProcessMonitor.h" >>> +#include "RegisterContextLinux_i386.h" >>> #include "RegisterContextLinux_x86_64.h" >>> #include "UnwindLLDB.h" >>> >>> @@ -59,11 +61,9 @@ LinuxThread::GetInfo() >>> lldb::RegisterContextSP >>> LinuxThread::GetRegisterContext() >>> { >>> - ProcessLinux &process = static_cast(GetProcess()); >>> - >>> if (!m_reg_context_sp) >>> { >>> - ArchSpec arch = process.GetTarget().GetArchitecture(); >>> + ArchSpec arch = Host::GetArchitecture(); >>> >>> switch (arch.GetCore()) >>> { >>> @@ -71,6 +71,12 @@ LinuxThread::GetRegisterContext() >>> assert(false && "CPU type not supported!"); >>> break; >>> >>> + case ArchSpec::eCore_x86_32_i386: >>> + case ArchSpec::eCore_x86_32_i486: >>> + case ArchSpec::eCore_x86_32_i486sx: >>> + m_reg_context_sp.reset(new RegisterContextLinux_i386(*this, 0)); >>> + break; >>> + >>> case ArchSpec::eCore_x86_64_x86_64: >>> m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0)); >>> break; >>> >> >> >> >> -- >> Marco Minutoli >> >> "If A is success in life, then A equals x plus y plus z. Work is x; >> y is play; and z is keeping your mouth shut." --A. Einstein > >> diff --git a/source/Plugins/Process/Linux/LinuxThread.cpp b/source/Plugins/Process/Linux/LinuxThread.cpp >> index 397d31b..8f3a273 100644 >> --- a/source/Plugins/Process/Linux/LinuxThread.cpp >> +++ b/source/Plugins/Process/Linux/LinuxThread.cpp >> @@ -12,6 +12,7 @@ >> >> // C++ Includes >> // Other libraries and framework includes >> +#include "lldb/Host/Host.h" >> #include "lldb/Target/Process.h" >> #include "lldb/Target/StopInfo.h" >> #include "lldb/Target/Target.h" >> @@ -19,6 +20,7 @@ >> #include "LinuxThread.h" >> #include "ProcessLinux.h" >> #include "ProcessMonitor.h" >> +#include "RegisterContextLinux_i386.h" >> #include "RegisterContextLinux_x86_64.h" >> #include "UnwindLLDB.h" >> >> @@ -63,7 +65,7 @@ LinuxThread::GetRegisterContext() >> >> if (!m_reg_context_sp) >> { >> - ArchSpec arch = process.GetTarget().GetArchitecture(); >> + ArchSpec arch = Host::GetArchitecture(); >> >> switch (arch.GetCore()) >> { >> @@ -71,6 +73,12 @@ LinuxThread::GetRegisterContext() >> assert(false && "CPU type not supported!"); >> break; >> >> + case ArchSpec::eCore_x86_32_i386: >> + case ArchSpec::eCore_x86_32_i486: >> + case ArchSpec::eCore_x86_32_i486sx: >> + m_reg_context_sp.reset(new RegisterContextLinux_i386(*this, 0)); >> + break; >> + >> case ArchSpec::eCore_x86_64_x86_64: >> m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0)); >> break; >> diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp b/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp >> new file mode 100644 >> index 0000000..b7451d2 >> --- /dev/null >> +++ b/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp >> @@ -0,0 +1,633 @@ >> +//===-- RegisterContextLinux_i386.cpp ----------------------------*- C++ -*-===// >> +// >> +// The LLVM Compiler Infrastructure >> +// >> +// This file is distributed under the University of Illinois Open Source >> +// License. See LICENSE.TXT for details. >> +// >> +//===----------------------------------------------------------------------===// >> + >> +#include "lldb/Core/DataExtractor.h" >> +#include "lldb/Target/Thread.h" >> +#include "lldb/Host/Endian.h" >> + >> +#include "ProcessLinux.h" >> +#include "ProcessMonitor.h" >> +#include "RegisterContextLinux_i386.h" >> + >> +using namespace lldb_private; >> +using namespace lldb; >> + >> +enum >> +{ >> + k_first_gpr, >> + gpr_eax = k_first_gpr, >> + gpr_ebx, >> + gpr_ecx, >> + gpr_edx, >> + gpr_edi, >> + gpr_esi, >> + gpr_ebp, >> + gpr_esp, >> + gpr_ss, >> + gpr_eflags, >> + gpr_orig_ax, >> + gpr_eip, >> + gpr_cs, >> + gpr_ds, >> + gpr_es, >> + gpr_fs, >> + gpr_gs, >> + k_last_gpr = gpr_gs, >> + >> + k_first_fpr, >> + fpu_fcw = k_first_fpr, >> + fpu_fsw, >> + fpu_ftw, >> + fpu_fop, >> + fpu_ip, >> + fpu_cs, >> + fpu_foo, >> + fpu_fos, >> + fpu_mxcsr, >> + fpu_stmm0, >> + fpu_stmm1, >> + fpu_stmm2, >> + fpu_stmm3, >> + fpu_stmm4, >> + fpu_stmm5, >> + fpu_stmm6, >> + fpu_stmm7, >> + fpu_xmm0, >> + fpu_xmm1, >> + fpu_xmm2, >> + fpu_xmm3, >> + fpu_xmm4, >> + fpu_xmm5, >> + fpu_xmm6, >> + fpu_xmm7, >> + k_last_fpr = fpu_xmm7, >> + >> + k_num_registers, >> + k_num_gpr_registers = k_last_gpr - k_first_gpr + 1, >> + k_num_fpu_registers = k_last_fpr - k_first_fpr + 1 >> +}; >> + >> +// Number of register sets provided by this context. >> +enum >> +{ >> + k_num_register_sets = 2 >> +}; >> + >> +enum >> +{ >> + gcc_eax = 0, >> + gcc_ecx, >> + gcc_edx, >> + gcc_ebx, >> + gcc_ebp, >> + gcc_esp, >> + gcc_esi, >> + gcc_edi, >> + gcc_eip, >> + gcc_eflags >> +}; >> + >> +enum >> +{ >> + dwarf_eax = 0, >> + dwarf_ecx, >> + dwarf_edx, >> + dwarf_ebx, >> + dwarf_esp, >> + dwarf_ebp, >> + dwarf_esi, >> + dwarf_edi, >> + dwarf_eip, >> + dwarf_eflags, >> + dwarf_stmm0 = 11, >> + dwarf_stmm1, >> + dwarf_stmm2, >> + dwarf_stmm3, >> + dwarf_stmm4, >> + dwarf_stmm5, >> + dwarf_stmm6, >> + dwarf_stmm7, >> + dwarf_xmm0 = 21, >> + dwarf_xmm1, >> + dwarf_xmm2, >> + dwarf_xmm3, >> + dwarf_xmm4, >> + dwarf_xmm5, >> + dwarf_xmm6, >> + dwarf_xmm7 >> +}; >> + >> +enum >> +{ >> + gdb_eax = 0, >> + gdb_ecx = 1, >> + gdb_edx = 2, >> + gdb_ebx = 3, >> + gdb_esp = 4, >> + gdb_ebp = 5, >> + gdb_esi = 6, >> + gdb_edi = 7, >> + gdb_eip = 8, >> + gdb_eflags = 9, >> + gdb_cs = 10, >> + gdb_ss = 11, >> + gdb_ds = 12, >> + gdb_es = 13, >> + gdb_fs = 14, >> + gdb_gs = 15, >> + gdb_stmm0 = 16, >> + gdb_stmm1 = 17, >> + gdb_stmm2 = 18, >> + gdb_stmm3 = 19, >> + gdb_stmm4 = 20, >> + gdb_stmm5 = 21, >> + gdb_stmm6 = 22, >> + gdb_stmm7 = 23, >> + gdb_fcw = 24, >> + gdb_fsw = 25, >> + gdb_ftw = 26, >> + gdb_fpu_cs = 27, >> + gdb_ip = 28, >> + gdb_fpu_ds = 29, >> + gdb_dp = 30, >> + gdb_fop = 31, >> + gdb_xmm0 = 32, >> + gdb_xmm1 = 33, >> + gdb_xmm2 = 34, >> + gdb_xmm3 = 35, >> + gdb_xmm4 = 36, >> + gdb_xmm5 = 37, >> + gdb_xmm6 = 38, >> + gdb_xmm7 = 39, >> + gdb_mxcsr = 40, >> + gdb_mm0 = 41, >> + gdb_mm1 = 42, >> + gdb_mm2 = 43, >> + gdb_mm3 = 44, >> + gdb_mm4 = 45, >> + gdb_mm5 = 46, >> + gdb_mm6 = 47, >> + gdb_mm7 = 48 >> +}; >> + >> +static const >> +uint32_t g_gpr_regnums[k_num_gpr_registers] = >> +{ >> + gpr_eax, >> + gpr_ebx, >> + gpr_ecx, >> + gpr_edx, >> + gpr_edi, >> + gpr_esi, >> + gpr_ebp, >> + gpr_esp, >> + gpr_ss, >> + gpr_eflags, >> + gpr_orig_ax, >> + gpr_eip, >> + gpr_cs, >> + gpr_ds, >> + gpr_es, >> + gpr_fs, >> + gpr_gs, >> +}; >> + >> +static const uint32_t >> +g_fpu_regnums[k_num_fpu_registers] = >> +{ >> + fpu_fcw, >> + fpu_fsw, >> + fpu_ftw, >> + fpu_fop, >> + fpu_ip, >> + fpu_cs, >> + fpu_foo, >> + fpu_fos, >> + fpu_mxcsr, >> + fpu_stmm0, >> + fpu_stmm1, >> + fpu_stmm2, >> + fpu_stmm3, >> + fpu_stmm4, >> + fpu_stmm5, >> + fpu_stmm6, >> + fpu_stmm7, >> + fpu_xmm0, >> + fpu_xmm1, >> + fpu_xmm2, >> + fpu_xmm3, >> + fpu_xmm4, >> + fpu_xmm5, >> + fpu_xmm6, >> + fpu_xmm7, >> +}; >> + >> +static const RegisterSet >> +g_reg_sets[k_num_register_sets] = >> +{ >> + { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums }, >> + { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums } >> +}; >> + >> +// Computes the offset of the given GPR in the user data area. >> +#define GPR_OFFSET(regname) \ >> + (offsetof(RegisterContextLinux_i386::UserArea, regs) + \ >> + offsetof(RegisterContextLinux_i386::GPR, regname)) >> + >> +// Computes the offset of the given FPR in the user data area. >> +#define FPR_OFFSET(regname) \ >> + (offsetof(RegisterContextLinux_i386::UserArea, i387) + \ >> + offsetof(RegisterContextLinux_i386::FPU, regname)) >> + >> +// Number of bytes needed to represent a GPR. >> +#define GPR_SIZE(reg) sizeof(((RegisterContextLinux_i386::GPR*)NULL)->reg) >> + >> +// Number of bytes needed to represent a FPR. >> +#define FPR_SIZE(reg) sizeof(((RegisterContextLinux_i386::FPU*)NULL)->reg) >> + >> +// Number of bytes needed to represent the i'th FP register. >> +#define FP_SIZE sizeof(((RegisterContextLinux_i386::MMSReg*)NULL)->bytes) >> + >> +// Number of bytes needed to represent an XMM register. >> +#define XMM_SIZE sizeof(RegisterContextLinux_i386::XMMReg) >> + >> +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ >> + { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \ >> + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg } } >> + >> +#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \ >> + { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ >> + eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg } } >> + >> +#define DEFINE_FP(reg, i) \ >> + { #reg#i, NULL, FP_SIZE, FPR_OFFSET(reg[i]), eEncodingVector, \ >> + eFormatVectorOfUInt8, \ >> + { dwarf_##reg##i, dwarf_##reg##i, \ >> + LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i } } >> + >> +#define DEFINE_XMM(reg, i) \ >> + { #reg#i, NULL, XMM_SIZE, FPR_OFFSET(reg[i]), eEncodingVector, \ >> + eFormatVectorOfUInt8, \ >> + { dwarf_##reg##i, dwarf_##reg##i, \ >> + LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i } } >> + >> +static RegisterInfo >> +g_register_infos[k_num_registers] = >> +{ >> + // General purpose registers. >> + DEFINE_GPR(eax, NULL, gcc_eax, dwarf_eax, LLDB_INVALID_REGNUM, gdb_eax), >> + DEFINE_GPR(ebx, NULL, gcc_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, gdb_ebx), >> + DEFINE_GPR(ecx, NULL, gcc_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, gdb_ecx), >> + DEFINE_GPR(edx, NULL, gcc_edx, dwarf_edx, LLDB_INVALID_REGNUM, gdb_edx), >> + DEFINE_GPR(edi, NULL, gcc_edi, dwarf_edi, LLDB_INVALID_REGNUM, gdb_edi), >> + DEFINE_GPR(esi, NULL, gcc_esi, dwarf_esi, LLDB_INVALID_REGNUM, gdb_esi), >> + DEFINE_GPR(ebp, "fp", gcc_ebp, dwarf_ebp, LLDB_INVALID_REGNUM, gdb_ebp), >> + DEFINE_GPR(esp, "sp", gcc_esp, dwarf_esp, LLDB_INVALID_REGNUM, gdb_esp), >> + DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ss), >> + DEFINE_GPR(eflags, "flags", gcc_eflags, dwarf_eflags, LLDB_INVALID_REGNUM, gdb_eflags), >> + DEFINE_GPR(eip, "pc", gcc_eip, dwarf_eip, LLDB_INVALID_REGNUM, gdb_eip), >> + DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_cs), >> + DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ds), >> + DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_es), >> + DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fs), >> + DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gs), >> + >> + // Floating point registers. >> + DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fcw), >> + DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fsw), >> + DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftw), >> + DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop), >> + DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ip), >> + DEFINE_FPR(cs, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs), >> + DEFINE_FPR(foo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_dp), >> + DEFINE_FPR(fos, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds), >> + DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_mxcsr), >> + >> + DEFINE_FP(stmm, 0), >> + DEFINE_FP(stmm, 1), >> + DEFINE_FP(stmm, 2), >> + DEFINE_FP(stmm, 3), >> + DEFINE_FP(stmm, 4), >> + DEFINE_FP(stmm, 5), >> + DEFINE_FP(stmm, 6), >> + DEFINE_FP(stmm, 7), >> + >> + // XMM registers >> + DEFINE_XMM(xmm, 0), >> + DEFINE_XMM(xmm, 1), >> + DEFINE_XMM(xmm, 2), >> + DEFINE_XMM(xmm, 3), >> + DEFINE_XMM(xmm, 4), >> + DEFINE_XMM(xmm, 5), >> + DEFINE_XMM(xmm, 6), >> + DEFINE_XMM(xmm, 7), >> + >> +}; >> + >> +static unsigned GetRegOffset(unsigned reg) >> +{ >> + assert(reg < k_num_registers && "Invalid register number."); >> + return g_register_infos[reg].byte_offset; >> +} >> + >> +static unsigned GetRegSize(unsigned reg) >> +{ >> + assert(reg < k_num_registers && "Invalid register number."); >> + return g_register_infos[reg].byte_size; >> +} >> + >> +static bool IsGPR(unsigned reg) >> +{ >> + return reg <= k_last_gpr; // GPR's come first. >> +} >> + >> +static bool IsFPR(unsigned reg) >> +{ >> + return (k_first_fpr <= reg && reg <= k_last_fpr); >> +} >> + >> + >> +RegisterContextLinux_i386::RegisterContextLinux_i386(Thread &thread, >> + uint32_t concrete_frame_idx) >> + : RegisterContextLinux(thread, concrete_frame_idx) >> +{ >> +} >> + >> +RegisterContextLinux_i386::~RegisterContextLinux_i386() >> +{ >> +} >> + >> +ProcessMonitor & >> +RegisterContextLinux_i386::GetMonitor() >> +{ >> + ProcessLinux *process = static_cast(CalculateProcess()); >> + return process->GetMonitor(); >> +} >> + >> +void >> +RegisterContextLinux_i386::Invalidate() >> +{ >> +} >> + >> +void >> +RegisterContextLinux_i386::InvalidateAllRegisters() >> +{ >> +} >> + >> +size_t >> +RegisterContextLinux_i386::GetRegisterCount() >> +{ >> + return k_num_registers; >> +} >> + >> +const RegisterInfo * >> +RegisterContextLinux_i386::GetRegisterInfoAtIndex(uint32_t reg) >> +{ >> + if (reg < k_num_registers) >> + return &g_register_infos[reg]; >> + else >> + return NULL; >> +} >> + >> +size_t >> +RegisterContextLinux_i386::GetRegisterSetCount() >> +{ >> + return k_num_register_sets; >> +} >> + >> +const RegisterSet * >> +RegisterContextLinux_i386::GetRegisterSet(uint32_t set) >> +{ >> + if (set < k_num_register_sets) >> + return &g_reg_sets[set]; >> + else >> + return NULL; >> +} >> + >> +bool >> +RegisterContextLinux_i386::ReadRegisterValue(uint32_t reg, >> + Scalar &value) >> +{ >> + ProcessMonitor &monitor = GetMonitor(); >> + return monitor.ReadRegisterValue(GetRegOffset(reg), value); >> +} >> + >> +bool >> +RegisterContextLinux_i386::ReadRegisterBytes(uint32_t reg, >> + DataExtractor &data) >> +{ >> + uint8_t *buf = reinterpret_cast(&user); >> + bool status; >> + >> + if (IsGPR(reg)) >> + status = ReadGPR(); >> + else if (IsFPR(reg)) >> + status = ReadFPR(); >> + else >> + { >> + assert(false && "invalid register number"); >> + status = false; >> + } >> + >> + if (status) >> + data.SetData(buf + GetRegOffset(reg), GetRegSize(reg), lldb::endian::InlHostByteOrder()); >> + >> + return status; >> +} >> + >> +bool >> +RegisterContextLinux_i386::ReadAllRegisterValues(DataBufferSP &data_sp) >> +{ >> + return false; >> +} >> + >> +bool >> +RegisterContextLinux_i386::WriteRegisterValue(uint32_t reg, >> + const Scalar &value) >> +{ >> + ProcessMonitor &monitor = GetMonitor(); >> + return monitor.WriteRegisterValue(GetRegOffset(reg), value); >> +} >> + >> +bool >> +RegisterContextLinux_i386::WriteRegisterBytes(uint32_t reg, >> + DataExtractor &data, >> + uint32_t data_offset) >> +{ >> + return false; >> +} >> + >> +bool >> +RegisterContextLinux_i386::WriteAllRegisterValues(const DataBufferSP &data) >> +{ >> + return false; >> +} >> + >> +bool >> +RegisterContextLinux_i386::UpdateAfterBreakpoint() >> +{ >> + // PC points one byte past the int3 responsible for the breakpoint. >> + lldb::addr_t pc; >> + >> + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) >> + return false; >> + >> + SetPC(pc - 1); >> + return true; >> +} >> + >> +uint32_t >> +RegisterContextLinux_i386::ConvertRegisterKindToRegisterNumber(uint32_t kind, >> + uint32_t num) >> +{ >> + if (kind == eRegisterKindGeneric) >> + { >> + switch (num) >> + { >> + case LLDB_REGNUM_GENERIC_PC: return gpr_eip; >> + case LLDB_REGNUM_GENERIC_SP: return gpr_esp; >> + case LLDB_REGNUM_GENERIC_FP: return gpr_ebp; >> + case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags; >> + case LLDB_REGNUM_GENERIC_RA: >> + default: >> + return LLDB_INVALID_REGNUM; >> + } >> + } >> + >> + if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF) >> + { >> + switch (num) >> + { >> + case dwarf_eax: return gpr_eax; >> + case dwarf_edx: return gpr_edx; >> + case dwarf_ecx: return gpr_ecx; >> + case dwarf_ebx: return gpr_ebx; >> + case dwarf_esi: return gpr_esi; >> + case dwarf_edi: return gpr_edi; >> + case dwarf_ebp: return gpr_ebp; >> + case dwarf_esp: return gpr_esp; >> + case dwarf_eip: return gpr_eip; >> + case dwarf_xmm0: return fpu_xmm0; >> + case dwarf_xmm1: return fpu_xmm1; >> + case dwarf_xmm2: return fpu_xmm2; >> + case dwarf_xmm3: return fpu_xmm3; >> + case dwarf_xmm4: return fpu_xmm4; >> + case dwarf_xmm5: return fpu_xmm5; >> + case dwarf_xmm6: return fpu_xmm6; >> + case dwarf_xmm7: return fpu_xmm7; >> + case dwarf_stmm0: return fpu_stmm0; >> + case dwarf_stmm1: return fpu_stmm1; >> + case dwarf_stmm2: return fpu_stmm2; >> + case dwarf_stmm3: return fpu_stmm3; >> + case dwarf_stmm4: return fpu_stmm4; >> + case dwarf_stmm5: return fpu_stmm5; >> + case dwarf_stmm6: return fpu_stmm6; >> + case dwarf_stmm7: return fpu_stmm7; >> + default: >> + return LLDB_INVALID_REGNUM; >> + } >> + } >> + >> + if (kind == eRegisterKindGDB) >> + { >> + switch (num) >> + { >> + case gdb_eax : return gpr_eax; >> + case gdb_ebx : return gpr_ebx; >> + case gdb_ecx : return gpr_ecx; >> + case gdb_edx : return gpr_edx; >> + case gdb_esi : return gpr_esi; >> + case gdb_edi : return gpr_edi; >> + case gdb_ebp : return gpr_ebp; >> + case gdb_esp : return gpr_esp; >> + case gdb_eip : return gpr_eip; >> + case gdb_eflags : return gpr_eflags; >> + case gdb_cs : return gpr_cs; >> + case gdb_ss : return gpr_ss; >> + case gdb_ds : return gpr_ds; >> + case gdb_es : return gpr_es; >> + case gdb_fs : return gpr_fs; >> + case gdb_gs : return gpr_gs; >> + case gdb_stmm0 : return fpu_stmm0; >> + case gdb_stmm1 : return fpu_stmm1; >> + case gdb_stmm2 : return fpu_stmm2; >> + case gdb_stmm3 : return fpu_stmm3; >> + case gdb_stmm4 : return fpu_stmm4; >> + case gdb_stmm5 : return fpu_stmm5; >> + case gdb_stmm6 : return fpu_stmm6; >> + case gdb_stmm7 : return fpu_stmm7; >> + case gdb_fcw : return fpu_fcw; >> + case gdb_fsw : return fpu_fsw; >> + case gdb_ftw : return fpu_ftw; >> + case gdb_fpu_cs : return fpu_cs; >> + case gdb_ip : return fpu_ip; >> + case gdb_fpu_ds : return fpu_fos; >> + case gdb_dp : return fpu_foo; >> + case gdb_fop : return fpu_fop; >> + case gdb_xmm0 : return fpu_xmm0; >> + case gdb_xmm1 : return fpu_xmm1; >> + case gdb_xmm2 : return fpu_xmm2; >> + case gdb_xmm3 : return fpu_xmm3; >> + case gdb_xmm4 : return fpu_xmm4; >> + case gdb_xmm5 : return fpu_xmm5; >> + case gdb_xmm6 : return fpu_xmm6; >> + case gdb_xmm7 : return fpu_xmm7; >> + case gdb_mxcsr : return fpu_mxcsr; >> + default: >> + return LLDB_INVALID_REGNUM; >> + } >> + } >> + else if (kind == eRegisterKindLLDB) >> + { >> + return num; >> + } >> + >> + return LLDB_INVALID_REGNUM; >> +} >> + >> +bool >> +RegisterContextLinux_i386::HardwareSingleStep(bool enable) >> +{ >> + enum { TRACE_BIT = 0x100 }; >> + uint64_t eflags; >> + >> + if ((eflags = ReadRegisterAsUnsigned(gpr_eflags, -1UL)) == -1UL) >> + return false; >> + >> + if (enable) >> + { >> + if (eflags & TRACE_BIT) >> + return true; >> + >> + eflags |= TRACE_BIT; >> + } >> + else >> + { >> + if (!(eflags & TRACE_BIT)) >> + return false; >> + >> + eflags &= ~TRACE_BIT; >> + } >> + >> + return WriteRegisterFromUnsigned(gpr_eflags, eflags); >> +} >> + >> +bool >> +RegisterContextLinux_i386::ReadGPR() >> +{ >> + ProcessMonitor &monitor = GetMonitor(); >> + return monitor.ReadGPR(&user.regs); >> +} >> + >> +bool >> +RegisterContextLinux_i386::ReadFPR() >> +{ >> + ProcessMonitor &monitor = GetMonitor(); >> + return monitor.ReadFPR(&user.i387); >> +} >> diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_i386.h b/source/Plugins/Process/Linux/RegisterContextLinux_i386.h >> new file mode 100644 >> index 0000000..30b3d70 >> --- /dev/null >> +++ b/source/Plugins/Process/Linux/RegisterContextLinux_i386.h >> @@ -0,0 +1,148 @@ >> +//===-- RegisterContextLinux_i386.h ------------------------------*- C++ -*-===// >> +// >> +// The LLVM Compiler Infrastructure >> +// >> +// This file is distributed under the University of Illinois Open Source >> +// License. See LICENSE.TXT for details. >> +// >> +//===----------------------------------------------------------------------===// >> + >> +#ifndef liblldb_RegisterContextLinux_i386_h_ >> +#define liblldb_RegisterContextLinux_i386_h_ >> + >> +// C Includes >> +// C++ Includes >> +// Other libraries and framework includes >> +// Project includes >> +#include "RegisterContextLinux.h" >> + >> +class RegisterContextLinux_i386 : public RegisterContextLinux >> +{ >> +public: >> + RegisterContextLinux_i386(lldb_private::Thread &thread, >> + uint32_t concreate_frame_idx); >> + >> + ~RegisterContextLinux_i386(); >> + >> + void >> + Invalidate(); >> + >> + void >> + InvalidateAllRegisters(); >> + >> + size_t >> + GetRegisterCount(); >> + >> + const lldb::RegisterInfo * >> + GetRegisterInfoAtIndex(uint32_t reg); >> + >> + size_t >> + GetRegisterSetCount(); >> + >> + const lldb::RegisterSet * >> + GetRegisterSet(uint32_t set); >> + >> + bool >> + ReadRegisterValue(uint32_t reg, lldb_private::Scalar &value); >> + >> + bool >> + ReadRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data); >> + >> + bool >> + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); >> + >> + bool >> + WriteRegisterValue(uint32_t reg, const lldb_private::Scalar &value); >> + >> + bool >> + WriteRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data, >> + uint32_t data_offset = 0); >> + >> + bool >> + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); >> + >> + uint32_t >> + ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); >> + >> + bool >> + HardwareSingleStep(bool enable); >> + >> + bool >> + UpdateAfterBreakpoint(); >> + >> + struct GPR >> + { >> + uint32_t ebx; >> + uint32_t ecx; >> + uint32_t edx; >> + uint32_t esi; >> + uint32_t edi; >> + uint32_t ebp; >> + uint32_t eax; >> + uint32_t ds; >> + uint32_t es; >> + uint32_t fs; >> + uint32_t gs; >> + uint32_t orig_ax; >> + uint32_t eip; >> + uint32_t cs; >> + uint32_t eflags; >> + uint32_t esp; >> + uint32_t ss; >> + }; >> + >> + struct MMSReg >> + { >> + uint8_t bytes[8]; >> + }; >> + >> + struct XMMReg >> + { >> + uint8_t bytes[16]; >> + }; >> + >> + struct FPU >> + { >> + uint16_t fcw; >> + uint16_t fsw; >> + uint16_t ftw; >> + uint16_t fop; >> + uint32_t ip; >> + uint32_t cs; >> + uint32_t foo; >> + uint32_t fos; >> + uint32_t mxcsr; >> + uint32_t reserved; >> + MMSReg stmm[8]; >> + XMMReg xmm[8]; >> + uint32_t pad[56]; >> + }; >> + >> + struct UserArea >> + { >> + GPR regs; // General purpose registers. >> + int32_t fpvalid; // True if FPU is being used. >> + FPU i387; // FPU registers. >> + uint32_t tsize; // Text segment size. >> + uint32_t dsize; // Data segment size. >> + uint32_t ssize; // Stack segment size. >> + uint32_t start_code; // VM address of text. >> + uint32_t start_stack; // VM address of stack bottom (top in rsp). >> + int32_t signal; // Signal causing core dump. >> + int32_t reserved; // Unused. >> + uint32_t ar0; // Location of GPR's. >> + FPU* fpstate; // Location of FPR's. >> + uint32_t magic; // Identifier for core dumps. >> + char u_comm[32]; // Command causing core dump. >> + uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7). >> + }; >> +private: >> + UserArea user; >> + >> + ProcessMonitor &GetMonitor(); >> + >> + bool ReadGPR(); >> + bool ReadFPR(); >> +}; >> + >> +#endif // #ifndef liblldb_RegisterContextLinux_i386_h_ > > > -- > steve > -------------- next part -------------- An HTML attachment was scrubbed... URL: http://lists.cs.uiuc.edu/pipermail/lldb-commits/attachments/20110228/5f9cd8fd/attachment-0001.html From ctice at apple.com Mon Feb 28 16:39:58 2011 From: ctice at apple.com (Caroline Tice) Date: Mon, 28 Feb 2011 22:39:58 -0000 Subject: [Lldb-commits] [lldb] r126692 - in /lldb/trunk/source/Plugins/Instruction/ARM: EmulateInstructionARM.cpp EmulateInstructionARM.h Message-ID: <20110228223958.A70C02A6C12C@llvm.org> Author: ctice Date: Mon Feb 28 16:39:58 2011 New Revision: 126692 URL: http://llvm.org/viewvc/llvm-project?rev=126692&view=rev Log: Add code to emulate LDRH (immediate, Thumb) arm instruction. Modified: lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.h Modified: lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp?rev=126692&r1=126691&r2=126692&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp (original) +++ lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp Mon Feb 28 16:39:58 2011 @@ -5870,6 +5870,159 @@ } return true; } + +// LDRH (immediate, Thumb) calculates an address from a base register value and an immediate offset, loads a +// halfword from memory, zero-extends it to form a 32-bit word, and writes it to a register. It can use offset, +// post-indexed, or pre-indexed addressing. +bool +EmulateInstructionARM::EmulateLDRHImmediate (ARMEncoding encoding) +{ +#if 0 + if ConditionPassed() then + EncodingSpecificOperations(); NullCheckIfThumbEE(n); + offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); + address = if index then offset_addr else R[n]; + data = MemU[address,2]; + if wback then R[n] = offset_addr; + if UnalignedSupport() || address<0> = ???0??? then + R[t] = ZeroExtend(data, 32); + else // Can only apply before ARMv7 + R[t] = bits(32) UNKNOWN; +#endif + + + bool success = false; + const uint32_t opcode = OpcodeAsUnsigned (&success); + if (!success) + return false; + + if (ConditionPassed()) + { + uint32_t t; + uint32_t n; + uint32_t imm32; + bool index; + bool add; + bool wback; + + // EncodingSpecificOperations(); NullCheckIfThumbEE(n); + switch (encoding) + { + case eEncodingT1: + // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:???0???, 32); + t = Bits32 (opcode, 2, 0); + n = Bits32 (opcode, 5, 3); + imm32 = Bits32 (opcode, 10, 6) << 1; + + // index = TRUE; add = TRUE; wback = FALSE; + index = true; + add = true; + wback = false; + + break; + + case eEncodingT2: + // if Rt == ???1111??? then SEE "Unallocated memory hints"; + // if Rn == ???1111??? then SEE LDRH (literal); + // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); + t = Bits32 (opcode, 15, 12); + n = Bits32 (opcode, 19, 16); + imm32 = Bits32 (opcode, 11, 0); + + // index = TRUE; add = TRUE; wback = FALSE; + index = true; + add = true; + wback = false; + + // if t == 13 then UNPREDICTABLE; + if (t == 13) + return false; + break; + + case eEncodingT3: + // if Rn == ???1111??? then SEE LDRH (literal); + // if Rt == ???1111??? && P == ???1??? && U == ???0??? && W == ???0??? then SEE "Unallocated memory hints"; + // if P == ???1??? && U == ???1??? && W == ???0??? then SEE LDRHT; + // if P == ???0??? && W == ???0??? then UNDEFINED; + if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8)) + return false; + + // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); + t = Bits32 (opcode, 15, 12); + n = Bits32 (opcode, 19, 16); + imm32 = Bits32 (opcode, 7, 0); + + // index = (P == ???1???); add = (U == ???1???); wback = (W == ???1???); + index = BitIsSet (opcode, 10); + add = BitIsSet (opcode, 9); + wback = BitIsSet (opcode, 8); + + // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; + if (BadReg (t) || (wback && (n == t))) + return false; + break; + + default: + return false; + } + + // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); + uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); + if (!success) + return false; + + addr_t offset_addr; + addr_t address; + + if (add) + offset_addr = Rn + imm32; + else + offset_addr = Rn - imm32; + + // address = if index then offset_addr else R[n]; + if (index) + address = offset_addr; + else + address = Rn; + + // data = MemU[address,2]; + Register base_reg; + base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); + + EmulateInstruction::Context context; + context.type = eContextRegisterLoad; + context.SetRegisterPlusOffset (base_reg, address - Rn); + + uint64_t data = MemURead (context, address, 2, 0, &success); + if (!success) + return false; + + // if wback then R[n] = offset_addr; + if (wback) + { + context.type = eContextAdjustBaseRegister; + context.SetAddress (offset_addr); + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) + return false; + } + + // if UnalignedSupport() || address<0> = ???0??? then + if (UnalignedSupport () || BitIsClear (address, 0)) + { + // R[t] = ZeroExtend(data, 32); + context.type = eContextRegisterLoad; + context.SetRegisterPlusOffset (base_reg, address - Rn); + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) + return false; + } + else // Can only apply before ARMv7 + { + // R[t] = bits(32) UNKNOWN; + WriteBits32Unknown (t); + } + } + return true; +} // Bitwise Exclusive OR (immediate) performs a bitwise exclusive OR of a register value and an immediate value, // and writes the result to the destination register. It can optionally update the condition flags based on @@ -7242,7 +7395,7 @@ { 0x0e500000, 0x04100000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDRImmediateARM, "ldr [ {#+/-}]" }, { 0x0e500010, 0x06100000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDRRegister, "ldr [ +/- {}] {!}" }, { 0x0e5f0000, 0x045f0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb , [...]"}, - { 0xfe500010, 0x06500000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb , [,+/-{, }]{!}" }, + { 0xfe500010, 0x06500000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb , [,+/-{, }]{!}" }, //---------------------------------------------------------------------- // Store instructions @@ -7481,6 +7634,9 @@ { 0xff7f0000, 0xf81f0000, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb ,[...]" }, { 0xfffffe00, 0x00005c00, ARMV6T2_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb ,[,]" }, { 0xfff00fc0, 0xf8100000, ARMV6T2_ABOVE, eEncodingT2, eSize32,&EmulateInstructionARM::EmulateLDRBRegister, "ldrb.w ,[,{,LSL #imm2>}]" }, + { 0xfffff800, 0x00008800, ARMV4T_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh , [{,#}]" }, + { 0xfff00000, 0xf8b00000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh.w ,[{,#}]" }, + { 0xfff00800, 0xf8300800, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh ,[,#+/-]{!}" }, //---------------------------------------------------------------------- // Store instructions Modified: lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.h?rev=126692&r1=126691&r2=126692&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.h (original) +++ lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.h Mon Feb 28 16:39:58 2011 @@ -600,7 +600,7 @@ // A8.6.73 LDRH (immediate, Thumb) - Encoding T1, T2 bool - EmulateLDRHImmediateThumb (ARMEncoding encoding); + EmulateLDRHImmediate (ARMEncoding encoding); // A8.6.75 LDRH (literal) - Encoding T1 bool From wilsons at start.ca Mon Feb 28 16:52:38 2011 From: wilsons at start.ca (Stephen Wilson) Date: Mon, 28 Feb 2011 22:52:38 -0000 Subject: [Lldb-commits] [lldb] r126696 - in /lldb/trunk/source/Plugins/Process/Linux: LinuxThread.cpp RegisterContextLinux_i386.cpp RegisterContextLinux_i386.h Message-ID: <20110228225238.E58A72A6C12C@llvm.org> Author: wilsons Date: Mon Feb 28 16:52:38 2011 New Revision: 126696 URL: http://llvm.org/viewvc/llvm-project?rev=126696&view=rev Log: Add register context for i386 on Linux. Patch by Marco Minutoli! Added: lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_i386.h Modified: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp Modified: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp?rev=126696&r1=126695&r2=126696&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp (original) +++ lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp Mon Feb 28 16:52:38 2011 @@ -12,6 +12,7 @@ // C++ Includes // Other libraries and framework includes +#include "lldb/Host/Host.h" #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" @@ -19,6 +20,7 @@ #include "LinuxThread.h" #include "ProcessLinux.h" #include "ProcessMonitor.h" +#include "RegisterContextLinux_i386.h" #include "RegisterContextLinux_x86_64.h" #include "UnwindLLDB.h" @@ -59,11 +61,9 @@ lldb::RegisterContextSP LinuxThread::GetRegisterContext() { - ProcessLinux &process = static_cast(GetProcess()); - if (!m_reg_context_sp) { - ArchSpec arch = process.GetTarget().GetArchitecture(); + ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { @@ -71,6 +71,12 @@ assert(false && "CPU type not supported!"); break; + case ArchSpec::eCore_x86_32_i386: + case ArchSpec::eCore_x86_32_i486: + case ArchSpec::eCore_x86_32_i486sx: + m_reg_context_sp.reset(new RegisterContextLinux_i386(*this, 0)); + break; + case ArchSpec::eCore_x86_64_x86_64: m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0)); break; @@ -99,7 +105,7 @@ if (frame) concrete_frame_idx = frame->GetConcreteFrameIndex(); - + if (concrete_frame_idx == 0) reg_ctx_sp = GetRegisterContext(); else Added: lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp?rev=126696&view=auto ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp (added) +++ lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp Mon Feb 28 16:52:38 2011 @@ -0,0 +1,633 @@ +//===-- RegisterContextLinux_i386.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/DataExtractor.h" +#include "lldb/Target/Thread.h" +#include "lldb/Host/Endian.h" + +#include "ProcessLinux.h" +#include "ProcessMonitor.h" +#include "RegisterContextLinux_i386.h" + +using namespace lldb_private; +using namespace lldb; + +enum +{ + k_first_gpr, + gpr_eax = k_first_gpr, + gpr_ebx, + gpr_ecx, + gpr_edx, + gpr_edi, + gpr_esi, + gpr_ebp, + gpr_esp, + gpr_ss, + gpr_eflags, + gpr_orig_ax, + gpr_eip, + gpr_cs, + gpr_ds, + gpr_es, + gpr_fs, + gpr_gs, + k_last_gpr = gpr_gs, + + k_first_fpr, + fpu_fcw = k_first_fpr, + fpu_fsw, + fpu_ftw, + fpu_fop, + fpu_ip, + fpu_cs, + fpu_foo, + fpu_fos, + fpu_mxcsr, + fpu_stmm0, + fpu_stmm1, + fpu_stmm2, + fpu_stmm3, + fpu_stmm4, + fpu_stmm5, + fpu_stmm6, + fpu_stmm7, + fpu_xmm0, + fpu_xmm1, + fpu_xmm2, + fpu_xmm3, + fpu_xmm4, + fpu_xmm5, + fpu_xmm6, + fpu_xmm7, + k_last_fpr = fpu_xmm7, + + k_num_registers, + k_num_gpr_registers = k_last_gpr - k_first_gpr + 1, + k_num_fpu_registers = k_last_fpr - k_first_fpr + 1 +}; + +// Number of register sets provided by this context. +enum +{ + k_num_register_sets = 2 +}; + +enum +{ + gcc_eax = 0, + gcc_ecx, + gcc_edx, + gcc_ebx, + gcc_ebp, + gcc_esp, + gcc_esi, + gcc_edi, + gcc_eip, + gcc_eflags +}; + +enum +{ + dwarf_eax = 0, + dwarf_ecx, + dwarf_edx, + dwarf_ebx, + dwarf_esp, + dwarf_ebp, + dwarf_esi, + dwarf_edi, + dwarf_eip, + dwarf_eflags, + dwarf_stmm0 = 11, + dwarf_stmm1, + dwarf_stmm2, + dwarf_stmm3, + dwarf_stmm4, + dwarf_stmm5, + dwarf_stmm6, + dwarf_stmm7, + dwarf_xmm0 = 21, + dwarf_xmm1, + dwarf_xmm2, + dwarf_xmm3, + dwarf_xmm4, + dwarf_xmm5, + dwarf_xmm6, + dwarf_xmm7 +}; + +enum +{ + gdb_eax = 0, + gdb_ecx = 1, + gdb_edx = 2, + gdb_ebx = 3, + gdb_esp = 4, + gdb_ebp = 5, + gdb_esi = 6, + gdb_edi = 7, + gdb_eip = 8, + gdb_eflags = 9, + gdb_cs = 10, + gdb_ss = 11, + gdb_ds = 12, + gdb_es = 13, + gdb_fs = 14, + gdb_gs = 15, + gdb_stmm0 = 16, + gdb_stmm1 = 17, + gdb_stmm2 = 18, + gdb_stmm3 = 19, + gdb_stmm4 = 20, + gdb_stmm5 = 21, + gdb_stmm6 = 22, + gdb_stmm7 = 23, + gdb_fcw = 24, + gdb_fsw = 25, + gdb_ftw = 26, + gdb_fpu_cs = 27, + gdb_ip = 28, + gdb_fpu_ds = 29, + gdb_dp = 30, + gdb_fop = 31, + gdb_xmm0 = 32, + gdb_xmm1 = 33, + gdb_xmm2 = 34, + gdb_xmm3 = 35, + gdb_xmm4 = 36, + gdb_xmm5 = 37, + gdb_xmm6 = 38, + gdb_xmm7 = 39, + gdb_mxcsr = 40, + gdb_mm0 = 41, + gdb_mm1 = 42, + gdb_mm2 = 43, + gdb_mm3 = 44, + gdb_mm4 = 45, + gdb_mm5 = 46, + gdb_mm6 = 47, + gdb_mm7 = 48 +}; + +static const +uint32_t g_gpr_regnums[k_num_gpr_registers] = +{ + gpr_eax, + gpr_ebx, + gpr_ecx, + gpr_edx, + gpr_edi, + gpr_esi, + gpr_ebp, + gpr_esp, + gpr_ss, + gpr_eflags, + gpr_orig_ax, + gpr_eip, + gpr_cs, + gpr_ds, + gpr_es, + gpr_fs, + gpr_gs, +}; + +static const uint32_t +g_fpu_regnums[k_num_fpu_registers] = +{ + fpu_fcw, + fpu_fsw, + fpu_ftw, + fpu_fop, + fpu_ip, + fpu_cs, + fpu_foo, + fpu_fos, + fpu_mxcsr, + fpu_stmm0, + fpu_stmm1, + fpu_stmm2, + fpu_stmm3, + fpu_stmm4, + fpu_stmm5, + fpu_stmm6, + fpu_stmm7, + fpu_xmm0, + fpu_xmm1, + fpu_xmm2, + fpu_xmm3, + fpu_xmm4, + fpu_xmm5, + fpu_xmm6, + fpu_xmm7, +}; + +static const RegisterSet +g_reg_sets[k_num_register_sets] = +{ + { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums }, + { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums } +}; + +// Computes the offset of the given GPR in the user data area. +#define GPR_OFFSET(regname) \ + (offsetof(RegisterContextLinux_i386::UserArea, regs) + \ + offsetof(RegisterContextLinux_i386::GPR, regname)) + +// Computes the offset of the given FPR in the user data area. +#define FPR_OFFSET(regname) \ + (offsetof(RegisterContextLinux_i386::UserArea, i387) + \ + offsetof(RegisterContextLinux_i386::FPU, regname)) + +// Number of bytes needed to represent a GPR. +#define GPR_SIZE(reg) sizeof(((RegisterContextLinux_i386::GPR*)NULL)->reg) + +// Number of bytes needed to represent a FPR. +#define FPR_SIZE(reg) sizeof(((RegisterContextLinux_i386::FPU*)NULL)->reg) + +// Number of bytes needed to represent the i'th FP register. +#define FP_SIZE sizeof(((RegisterContextLinux_i386::MMSReg*)NULL)->bytes) + +// Number of bytes needed to represent an XMM register. +#define XMM_SIZE sizeof(RegisterContextLinux_i386::XMMReg) + +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ + { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg } } + +#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \ + { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ + eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg } } + +#define DEFINE_FP(reg, i) \ + { #reg#i, NULL, FP_SIZE, FPR_OFFSET(reg[i]), eEncodingVector, \ + eFormatVectorOfUInt8, \ + { dwarf_##reg##i, dwarf_##reg##i, \ + LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i } } + +#define DEFINE_XMM(reg, i) \ + { #reg#i, NULL, XMM_SIZE, FPR_OFFSET(reg[i]), eEncodingVector, \ + eFormatVectorOfUInt8, \ + { dwarf_##reg##i, dwarf_##reg##i, \ + LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i } } + +static RegisterInfo +g_register_infos[k_num_registers] = +{ + // General purpose registers. + DEFINE_GPR(eax, NULL, gcc_eax, dwarf_eax, LLDB_INVALID_REGNUM, gdb_eax), + DEFINE_GPR(ebx, NULL, gcc_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, gdb_ebx), + DEFINE_GPR(ecx, NULL, gcc_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, gdb_ecx), + DEFINE_GPR(edx, NULL, gcc_edx, dwarf_edx, LLDB_INVALID_REGNUM, gdb_edx), + DEFINE_GPR(edi, NULL, gcc_edi, dwarf_edi, LLDB_INVALID_REGNUM, gdb_edi), + DEFINE_GPR(esi, NULL, gcc_esi, dwarf_esi, LLDB_INVALID_REGNUM, gdb_esi), + DEFINE_GPR(ebp, "fp", gcc_ebp, dwarf_ebp, LLDB_INVALID_REGNUM, gdb_ebp), + DEFINE_GPR(esp, "sp", gcc_esp, dwarf_esp, LLDB_INVALID_REGNUM, gdb_esp), + DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ss), + DEFINE_GPR(eflags, "flags", gcc_eflags, dwarf_eflags, LLDB_INVALID_REGNUM, gdb_eflags), + DEFINE_GPR(eip, "pc", gcc_eip, dwarf_eip, LLDB_INVALID_REGNUM, gdb_eip), + DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_cs), + DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ds), + DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_es), + DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fs), + DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gs), + + // Floating point registers. + DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fcw), + DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fsw), + DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftw), + DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop), + DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ip), + DEFINE_FPR(cs, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs), + DEFINE_FPR(foo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_dp), + DEFINE_FPR(fos, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds), + DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_mxcsr), + + DEFINE_FP(stmm, 0), + DEFINE_FP(stmm, 1), + DEFINE_FP(stmm, 2), + DEFINE_FP(stmm, 3), + DEFINE_FP(stmm, 4), + DEFINE_FP(stmm, 5), + DEFINE_FP(stmm, 6), + DEFINE_FP(stmm, 7), + + // XMM registers + DEFINE_XMM(xmm, 0), + DEFINE_XMM(xmm, 1), + DEFINE_XMM(xmm, 2), + DEFINE_XMM(xmm, 3), + DEFINE_XMM(xmm, 4), + DEFINE_XMM(xmm, 5), + DEFINE_XMM(xmm, 6), + DEFINE_XMM(xmm, 7), + +}; + +static unsigned GetRegOffset(unsigned reg) +{ + assert(reg < k_num_registers && "Invalid register number."); + return g_register_infos[reg].byte_offset; +} + +static unsigned GetRegSize(unsigned reg) +{ + assert(reg < k_num_registers && "Invalid register number."); + return g_register_infos[reg].byte_size; +} + +static bool IsGPR(unsigned reg) +{ + return reg <= k_last_gpr; // GPR's come first. +} + +static bool IsFPR(unsigned reg) +{ + return (k_first_fpr <= reg && reg <= k_last_fpr); +} + + +RegisterContextLinux_i386::RegisterContextLinux_i386(Thread &thread, + uint32_t concrete_frame_idx) + : RegisterContextLinux(thread, concrete_frame_idx) +{ +} + +RegisterContextLinux_i386::~RegisterContextLinux_i386() +{ +} + +ProcessMonitor & +RegisterContextLinux_i386::GetMonitor() +{ + ProcessLinux *process = static_cast(CalculateProcess()); + return process->GetMonitor(); +} + +void +RegisterContextLinux_i386::Invalidate() +{ +} + +void +RegisterContextLinux_i386::InvalidateAllRegisters() +{ +} + +size_t +RegisterContextLinux_i386::GetRegisterCount() +{ + return k_num_registers; +} + +const RegisterInfo * +RegisterContextLinux_i386::GetRegisterInfoAtIndex(uint32_t reg) +{ + if (reg < k_num_registers) + return &g_register_infos[reg]; + else + return NULL; +} + +size_t +RegisterContextLinux_i386::GetRegisterSetCount() +{ + return k_num_register_sets; +} + +const RegisterSet * +RegisterContextLinux_i386::GetRegisterSet(uint32_t set) +{ + if (set < k_num_register_sets) + return &g_reg_sets[set]; + else + return NULL; +} + +bool +RegisterContextLinux_i386::ReadRegisterValue(uint32_t reg, + Scalar &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadRegisterValue(GetRegOffset(reg), value); +} + +bool +RegisterContextLinux_i386::ReadRegisterBytes(uint32_t reg, + DataExtractor &data) +{ + uint8_t *buf = reinterpret_cast(&user); + bool status; + + if (IsGPR(reg)) + status = ReadGPR(); + else if (IsFPR(reg)) + status = ReadFPR(); + else + { + assert(false && "invalid register number"); + status = false; + } + + if (status) + data.SetData(buf + GetRegOffset(reg), GetRegSize(reg), lldb::endian::InlHostByteOrder()); + + return status; +} + +bool +RegisterContextLinux_i386::ReadAllRegisterValues(DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextLinux_i386::WriteRegisterValue(uint32_t reg, + const Scalar &value) +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.WriteRegisterValue(GetRegOffset(reg), value); +} + +bool +RegisterContextLinux_i386::WriteRegisterBytes(uint32_t reg, + DataExtractor &data, + uint32_t data_offset) +{ + return false; +} + +bool +RegisterContextLinux_i386::WriteAllRegisterValues(const DataBufferSP &data) +{ + return false; +} + +bool +RegisterContextLinux_i386::UpdateAfterBreakpoint() +{ + // PC points one byte past the int3 responsible for the breakpoint. + lldb::addr_t pc; + + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) + return false; + + SetPC(pc - 1); + return true; +} + +uint32_t +RegisterContextLinux_i386::ConvertRegisterKindToRegisterNumber(uint32_t kind, + uint32_t num) +{ + if (kind == eRegisterKindGeneric) + { + switch (num) + { + case LLDB_REGNUM_GENERIC_PC: return gpr_eip; + case LLDB_REGNUM_GENERIC_SP: return gpr_esp; + case LLDB_REGNUM_GENERIC_FP: return gpr_ebp; + case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags; + case LLDB_REGNUM_GENERIC_RA: + default: + return LLDB_INVALID_REGNUM; + } + } + + if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF) + { + switch (num) + { + case dwarf_eax: return gpr_eax; + case dwarf_edx: return gpr_edx; + case dwarf_ecx: return gpr_ecx; + case dwarf_ebx: return gpr_ebx; + case dwarf_esi: return gpr_esi; + case dwarf_edi: return gpr_edi; + case dwarf_ebp: return gpr_ebp; + case dwarf_esp: return gpr_esp; + case dwarf_eip: return gpr_eip; + case dwarf_xmm0: return fpu_xmm0; + case dwarf_xmm1: return fpu_xmm1; + case dwarf_xmm2: return fpu_xmm2; + case dwarf_xmm3: return fpu_xmm3; + case dwarf_xmm4: return fpu_xmm4; + case dwarf_xmm5: return fpu_xmm5; + case dwarf_xmm6: return fpu_xmm6; + case dwarf_xmm7: return fpu_xmm7; + case dwarf_stmm0: return fpu_stmm0; + case dwarf_stmm1: return fpu_stmm1; + case dwarf_stmm2: return fpu_stmm2; + case dwarf_stmm3: return fpu_stmm3; + case dwarf_stmm4: return fpu_stmm4; + case dwarf_stmm5: return fpu_stmm5; + case dwarf_stmm6: return fpu_stmm6; + case dwarf_stmm7: return fpu_stmm7; + default: + return LLDB_INVALID_REGNUM; + } + } + + if (kind == eRegisterKindGDB) + { + switch (num) + { + case gdb_eax : return gpr_eax; + case gdb_ebx : return gpr_ebx; + case gdb_ecx : return gpr_ecx; + case gdb_edx : return gpr_edx; + case gdb_esi : return gpr_esi; + case gdb_edi : return gpr_edi; + case gdb_ebp : return gpr_ebp; + case gdb_esp : return gpr_esp; + case gdb_eip : return gpr_eip; + case gdb_eflags : return gpr_eflags; + case gdb_cs : return gpr_cs; + case gdb_ss : return gpr_ss; + case gdb_ds : return gpr_ds; + case gdb_es : return gpr_es; + case gdb_fs : return gpr_fs; + case gdb_gs : return gpr_gs; + case gdb_stmm0 : return fpu_stmm0; + case gdb_stmm1 : return fpu_stmm1; + case gdb_stmm2 : return fpu_stmm2; + case gdb_stmm3 : return fpu_stmm3; + case gdb_stmm4 : return fpu_stmm4; + case gdb_stmm5 : return fpu_stmm5; + case gdb_stmm6 : return fpu_stmm6; + case gdb_stmm7 : return fpu_stmm7; + case gdb_fcw : return fpu_fcw; + case gdb_fsw : return fpu_fsw; + case gdb_ftw : return fpu_ftw; + case gdb_fpu_cs : return fpu_cs; + case gdb_ip : return fpu_ip; + case gdb_fpu_ds : return fpu_fos; + case gdb_dp : return fpu_foo; + case gdb_fop : return fpu_fop; + case gdb_xmm0 : return fpu_xmm0; + case gdb_xmm1 : return fpu_xmm1; + case gdb_xmm2 : return fpu_xmm2; + case gdb_xmm3 : return fpu_xmm3; + case gdb_xmm4 : return fpu_xmm4; + case gdb_xmm5 : return fpu_xmm5; + case gdb_xmm6 : return fpu_xmm6; + case gdb_xmm7 : return fpu_xmm7; + case gdb_mxcsr : return fpu_mxcsr; + default: + return LLDB_INVALID_REGNUM; + } + } + else if (kind == eRegisterKindLLDB) + { + return num; + } + + return LLDB_INVALID_REGNUM; +} + +bool +RegisterContextLinux_i386::HardwareSingleStep(bool enable) +{ + enum { TRACE_BIT = 0x100 }; + uint64_t eflags; + + if ((eflags = ReadRegisterAsUnsigned(gpr_eflags, -1UL)) == -1UL) + return false; + + if (enable) + { + if (eflags & TRACE_BIT) + return true; + + eflags |= TRACE_BIT; + } + else + { + if (!(eflags & TRACE_BIT)) + return false; + + eflags &= ~TRACE_BIT; + } + + return WriteRegisterFromUnsigned(gpr_eflags, eflags); +} + +bool +RegisterContextLinux_i386::ReadGPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadGPR(&user.regs); +} + +bool +RegisterContextLinux_i386::ReadFPR() +{ + ProcessMonitor &monitor = GetMonitor(); + return monitor.ReadFPR(&user.i387); +} Added: lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_i386.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_i386.h?rev=126696&view=auto ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_i386.h (added) +++ lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_i386.h Mon Feb 28 16:52:38 2011 @@ -0,0 +1,148 @@ +//===-- RegisterContextLinux_i386.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextLinux_i386_h_ +#define liblldb_RegisterContextLinux_i386_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "RegisterContextLinux.h" + +class RegisterContextLinux_i386 : public RegisterContextLinux +{ +public: + RegisterContextLinux_i386(lldb_private::Thread &thread, + uint32_t concreate_frame_idx); + + ~RegisterContextLinux_i386(); + + void + Invalidate(); + + void + InvalidateAllRegisters(); + + size_t + GetRegisterCount(); + + const lldb::RegisterInfo * + GetRegisterInfoAtIndex(uint32_t reg); + + size_t + GetRegisterSetCount(); + + const lldb::RegisterSet * + GetRegisterSet(uint32_t set); + + bool + ReadRegisterValue(uint32_t reg, lldb_private::Scalar &value); + + bool + ReadRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteRegisterValue(uint32_t reg, const lldb_private::Scalar &value); + + bool + WriteRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data, + uint32_t data_offset = 0); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + uint32_t + ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); + + bool + HardwareSingleStep(bool enable); + + bool + UpdateAfterBreakpoint(); + + struct GPR + { + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t eax; + uint32_t ds; + uint32_t es; + uint32_t fs; + uint32_t gs; + uint32_t orig_ax; + uint32_t eip; + uint32_t cs; + uint32_t eflags; + uint32_t esp; + uint32_t ss; + }; + + struct MMSReg + { + uint8_t bytes[8]; + }; + + struct XMMReg + { + uint8_t bytes[16]; + }; + + struct FPU + { + uint16_t fcw; + uint16_t fsw; + uint16_t ftw; + uint16_t fop; + uint32_t ip; + uint32_t cs; + uint32_t foo; + uint32_t fos; + uint32_t mxcsr; + uint32_t reserved; + MMSReg stmm[8]; + XMMReg xmm[8]; + uint32_t pad[56]; + }; + + struct UserArea + { + GPR regs; // General purpose registers. + int32_t fpvalid; // True if FPU is being used. + FPU i387; // FPU registers. + uint32_t tsize; // Text segment size. + uint32_t dsize; // Data segment size. + uint32_t ssize; // Stack segment size. + uint32_t start_code; // VM address of text. + uint32_t start_stack; // VM address of stack bottom (top in rsp). + int32_t signal; // Signal causing core dump. + int32_t reserved; // Unused. + uint32_t ar0; // Location of GPR's. + FPU* fpstate; // Location of FPR's. + uint32_t magic; // Identifier for core dumps. + char u_comm[32]; // Command causing core dump. + uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7). + }; +private: + UserArea user; + + ProcessMonitor &GetMonitor(); + + bool ReadGPR(); + bool ReadFPR(); +}; + +#endif // #ifndef liblldb_RegisterContextLinux_i386_h_ From wilsons at start.ca Mon Feb 28 17:02:22 2011 From: wilsons at start.ca (Stephen Wilson) Date: Mon, 28 Feb 2011 18:02:22 -0500 Subject: [Lldb-commits] x86_32 linux support In-Reply-To: <306AEF9B-A50B-4464-BE32-1FAC51DBAB4A@apple.com> References: <20110226002555.GA11412@fibrous.localdomain> <20110226215800.GA17824@fibrous.localdomain> <306AEF9B-A50B-4464-BE32-1FAC51DBAB4A@apple.com> Message-ID: <20110228230221.GA26901@fibrous.localdomain> On Mon, Feb 28, 2011 at 11:30:48AM -0800, Greg Clayton wrote: > > On Feb 26, 2011, at 1:58 PM, Stephen Wilson wrote: > > > Marco, Greg, > > > > On Sat, Feb 26, 2011 at 03:09:45PM +0100, Marco Minutoli wrote: > >> Here is the patch with the changes you have requested. > > > > Nice. This looks good. > > > > > > Greg, mind if I commit this one? There is one trivial tweak needed to > > avoid a compile time warning. > > I am happy with letting you OK the any linux specific patches. If it > touches anyting in the core that is significant, then let me know, > else I will let you OK the linux patches, is that alright? OK. That sounds good to me. Of course, I will always appreciate any review/suggestions of the linux specific stuff post-commit. Committed in r126696. > > > >> Sorry for the duplicated header here It was late night(or maybe early > >> in the morning :D) when I sent the patch to the ML. Next time I'll be > >> more careful. > > > > No worries! We still have a bit of work to do to support i386 on linux > > but this is a significant step forward. Thanks so much! > > > > > >> Best regards, > >> Marco > >> > >> On Sat, Feb 26, 2011 at 1:25 AM, Stephen Wilson wrote: > >>> On Fri, Feb 25, 2011 at 02:52:51AM +0100, Marco Minutoli wrote: > >>>> Hi everybody, > >>>> > >>>> as suggested by Stephen I had a look at the user_32.h Linux header and > >>>> I fixed the UserArea structure. > >>>> > >>>> In the attachment the revised patch. As ever comments and suggestions > >>>> are welcome :). > >>> > >>> This looks good. Only two small issues: the patch for > >>> RegisterContextLinux_i386.h contains the old and new versions of your > >>> patch (the latter is protected behind an #ifndef). Also, I think we > >>> need the following patch for LinuxThread.cpp: Use a register context > >>> according to the host instead of the process target so we can debug and > >>> test lldb using 32-bit binaries on 64-bit systems. > >>> > >>> I have not been able to test your patch much yet -- another issue has > >>> crept into the linux builds that I need to track down first... but with > >>> those changes I think the patches can go in. > >>> > >>> > >>> > >>> Thanks again! > >>> > >>> > >>> diff --git a/source/Plugins/Process/Linux/LinuxThread.cpp b/source/Plugins/Process/Linux/LinuxThread.cpp > >>> index 397d31b..15bc9e3 100644 > >>> --- a/source/Plugins/Process/Linux/LinuxThread.cpp > >>> +++ b/source/Plugins/Process/Linux/LinuxThread.cpp > >>> @@ -12,6 +12,7 @@ > >>> > >>> // C++ Includes > >>> // Other libraries and framework includes > >>> +#include "lldb/Host/Host.h" > >>> #include "lldb/Target/Process.h" > >>> #include "lldb/Target/StopInfo.h" > >>> #include "lldb/Target/Target.h" > >>> @@ -19,6 +20,7 @@ > >>> #include "LinuxThread.h" > >>> #include "ProcessLinux.h" > >>> #include "ProcessMonitor.h" > >>> +#include "RegisterContextLinux_i386.h" > >>> #include "RegisterContextLinux_x86_64.h" > >>> #include "UnwindLLDB.h" > >>> > >>> @@ -59,11 +61,9 @@ LinuxThread::GetInfo() > >>> lldb::RegisterContextSP > >>> LinuxThread::GetRegisterContext() > >>> { > >>> - ProcessLinux &process = static_cast(GetProcess()); > >>> - > >>> if (!m_reg_context_sp) > >>> { > >>> - ArchSpec arch = process.GetTarget().GetArchitecture(); > >>> + ArchSpec arch = Host::GetArchitecture(); > >>> > >>> switch (arch.GetCore()) > >>> { > >>> @@ -71,6 +71,12 @@ LinuxThread::GetRegisterContext() > >>> assert(false && "CPU type not supported!"); > >>> break; > >>> > >>> + case ArchSpec::eCore_x86_32_i386: > >>> + case ArchSpec::eCore_x86_32_i486: > >>> + case ArchSpec::eCore_x86_32_i486sx: > >>> + m_reg_context_sp.reset(new RegisterContextLinux_i386(*this, 0)); > >>> + break; > >>> + > >>> case ArchSpec::eCore_x86_64_x86_64: > >>> m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0)); > >>> break; > >>> > >> > >> > >> > >> -- > >> Marco Minutoli > >> > >> "If A is success in life, then A equals x plus y plus z. Work is x; > >> y is play; and z is keeping your mouth shut." --A. Einstein > > > >> diff --git a/source/Plugins/Process/Linux/LinuxThread.cpp b/source/Plugins/Process/Linux/LinuxThread.cpp > >> index 397d31b..8f3a273 100644 > >> --- a/source/Plugins/Process/Linux/LinuxThread.cpp > >> +++ b/source/Plugins/Process/Linux/LinuxThread.cpp > >> @@ -12,6 +12,7 @@ > >> > >> // C++ Includes > >> // Other libraries and framework includes > >> +#include "lldb/Host/Host.h" > >> #include "lldb/Target/Process.h" > >> #include "lldb/Target/StopInfo.h" > >> #include "lldb/Target/Target.h" > >> @@ -19,6 +20,7 @@ > >> #include "LinuxThread.h" > >> #include "ProcessLinux.h" > >> #include "ProcessMonitor.h" > >> +#include "RegisterContextLinux_i386.h" > >> #include "RegisterContextLinux_x86_64.h" > >> #include "UnwindLLDB.h" > >> > >> @@ -63,7 +65,7 @@ LinuxThread::GetRegisterContext() > >> > >> if (!m_reg_context_sp) > >> { > >> - ArchSpec arch = process.GetTarget().GetArchitecture(); > >> + ArchSpec arch = Host::GetArchitecture(); > >> > >> switch (arch.GetCore()) > >> { > >> @@ -71,6 +73,12 @@ LinuxThread::GetRegisterContext() > >> assert(false && "CPU type not supported!"); > >> break; > >> > >> + case ArchSpec::eCore_x86_32_i386: > >> + case ArchSpec::eCore_x86_32_i486: > >> + case ArchSpec::eCore_x86_32_i486sx: > >> + m_reg_context_sp.reset(new RegisterContextLinux_i386(*this, 0)); > >> + break; > >> + > >> case ArchSpec::eCore_x86_64_x86_64: > >> m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0)); > >> break; > >> diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp b/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp > >> new file mode 100644 > >> index 0000000..b7451d2 > >> --- /dev/null > >> +++ b/source/Plugins/Process/Linux/RegisterContextLinux_i386.cpp > >> @@ -0,0 +1,633 @@ > >> +//===-- RegisterContextLinux_i386.cpp ----------------------------*- C++ -*-===// > >> +// > >> +// The LLVM Compiler Infrastructure > >> +// > >> +// This file is distributed under the University of Illinois Open Source > >> +// License. See LICENSE.TXT for details. > >> +// > >> +//===----------------------------------------------------------------------===// > >> + > >> +#include "lldb/Core/DataExtractor.h" > >> +#include "lldb/Target/Thread.h" > >> +#include "lldb/Host/Endian.h" > >> + > >> +#include "ProcessLinux.h" > >> +#include "ProcessMonitor.h" > >> +#include "RegisterContextLinux_i386.h" > >> + > >> +using namespace lldb_private; > >> +using namespace lldb; > >> + > >> +enum > >> +{ > >> + k_first_gpr, > >> + gpr_eax = k_first_gpr, > >> + gpr_ebx, > >> + gpr_ecx, > >> + gpr_edx, > >> + gpr_edi, > >> + gpr_esi, > >> + gpr_ebp, > >> + gpr_esp, > >> + gpr_ss, > >> + gpr_eflags, > >> + gpr_orig_ax, > >> + gpr_eip, > >> + gpr_cs, > >> + gpr_ds, > >> + gpr_es, > >> + gpr_fs, > >> + gpr_gs, > >> + k_last_gpr = gpr_gs, > >> + > >> + k_first_fpr, > >> + fpu_fcw = k_first_fpr, > >> + fpu_fsw, > >> + fpu_ftw, > >> + fpu_fop, > >> + fpu_ip, > >> + fpu_cs, > >> + fpu_foo, > >> + fpu_fos, > >> + fpu_mxcsr, > >> + fpu_stmm0, > >> + fpu_stmm1, > >> + fpu_stmm2, > >> + fpu_stmm3, > >> + fpu_stmm4, > >> + fpu_stmm5, > >> + fpu_stmm6, > >> + fpu_stmm7, > >> + fpu_xmm0, > >> + fpu_xmm1, > >> + fpu_xmm2, > >> + fpu_xmm3, > >> + fpu_xmm4, > >> + fpu_xmm5, > >> + fpu_xmm6, > >> + fpu_xmm7, > >> + k_last_fpr = fpu_xmm7, > >> + > >> + k_num_registers, > >> + k_num_gpr_registers = k_last_gpr - k_first_gpr + 1, > >> + k_num_fpu_registers = k_last_fpr - k_first_fpr + 1 > >> +}; > >> + > >> +// Number of register sets provided by this context. > >> +enum > >> +{ > >> + k_num_register_sets = 2 > >> +}; > >> + > >> +enum > >> +{ > >> + gcc_eax = 0, > >> + gcc_ecx, > >> + gcc_edx, > >> + gcc_ebx, > >> + gcc_ebp, > >> + gcc_esp, > >> + gcc_esi, > >> + gcc_edi, > >> + gcc_eip, > >> + gcc_eflags > >> +}; > >> + > >> +enum > >> +{ > >> + dwarf_eax = 0, > >> + dwarf_ecx, > >> + dwarf_edx, > >> + dwarf_ebx, > >> + dwarf_esp, > >> + dwarf_ebp, > >> + dwarf_esi, > >> + dwarf_edi, > >> + dwarf_eip, > >> + dwarf_eflags, > >> + dwarf_stmm0 = 11, > >> + dwarf_stmm1, > >> + dwarf_stmm2, > >> + dwarf_stmm3, > >> + dwarf_stmm4, > >> + dwarf_stmm5, > >> + dwarf_stmm6, > >> + dwarf_stmm7, > >> + dwarf_xmm0 = 21, > >> + dwarf_xmm1, > >> + dwarf_xmm2, > >> + dwarf_xmm3, > >> + dwarf_xmm4, > >> + dwarf_xmm5, > >> + dwarf_xmm6, > >> + dwarf_xmm7 > >> +}; > >> + > >> +enum > >> +{ > >> + gdb_eax = 0, > >> + gdb_ecx = 1, > >> + gdb_edx = 2, > >> + gdb_ebx = 3, > >> + gdb_esp = 4, > >> + gdb_ebp = 5, > >> + gdb_esi = 6, > >> + gdb_edi = 7, > >> + gdb_eip = 8, > >> + gdb_eflags = 9, > >> + gdb_cs = 10, > >> + gdb_ss = 11, > >> + gdb_ds = 12, > >> + gdb_es = 13, > >> + gdb_fs = 14, > >> + gdb_gs = 15, > >> + gdb_stmm0 = 16, > >> + gdb_stmm1 = 17, > >> + gdb_stmm2 = 18, > >> + gdb_stmm3 = 19, > >> + gdb_stmm4 = 20, > >> + gdb_stmm5 = 21, > >> + gdb_stmm6 = 22, > >> + gdb_stmm7 = 23, > >> + gdb_fcw = 24, > >> + gdb_fsw = 25, > >> + gdb_ftw = 26, > >> + gdb_fpu_cs = 27, > >> + gdb_ip = 28, > >> + gdb_fpu_ds = 29, > >> + gdb_dp = 30, > >> + gdb_fop = 31, > >> + gdb_xmm0 = 32, > >> + gdb_xmm1 = 33, > >> + gdb_xmm2 = 34, > >> + gdb_xmm3 = 35, > >> + gdb_xmm4 = 36, > >> + gdb_xmm5 = 37, > >> + gdb_xmm6 = 38, > >> + gdb_xmm7 = 39, > >> + gdb_mxcsr = 40, > >> + gdb_mm0 = 41, > >> + gdb_mm1 = 42, > >> + gdb_mm2 = 43, > >> + gdb_mm3 = 44, > >> + gdb_mm4 = 45, > >> + gdb_mm5 = 46, > >> + gdb_mm6 = 47, > >> + gdb_mm7 = 48 > >> +}; > >> + > >> +static const > >> +uint32_t g_gpr_regnums[k_num_gpr_registers] = > >> +{ > >> + gpr_eax, > >> + gpr_ebx, > >> + gpr_ecx, > >> + gpr_edx, > >> + gpr_edi, > >> + gpr_esi, > >> + gpr_ebp, > >> + gpr_esp, > >> + gpr_ss, > >> + gpr_eflags, > >> + gpr_orig_ax, > >> + gpr_eip, > >> + gpr_cs, > >> + gpr_ds, > >> + gpr_es, > >> + gpr_fs, > >> + gpr_gs, > >> +}; > >> + > >> +static const uint32_t > >> +g_fpu_regnums[k_num_fpu_registers] = > >> +{ > >> + fpu_fcw, > >> + fpu_fsw, > >> + fpu_ftw, > >> + fpu_fop, > >> + fpu_ip, > >> + fpu_cs, > >> + fpu_foo, > >> + fpu_fos, > >> + fpu_mxcsr, > >> + fpu_stmm0, > >> + fpu_stmm1, > >> + fpu_stmm2, > >> + fpu_stmm3, > >> + fpu_stmm4, > >> + fpu_stmm5, > >> + fpu_stmm6, > >> + fpu_stmm7, > >> + fpu_xmm0, > >> + fpu_xmm1, > >> + fpu_xmm2, > >> + fpu_xmm3, > >> + fpu_xmm4, > >> + fpu_xmm5, > >> + fpu_xmm6, > >> + fpu_xmm7, > >> +}; > >> + > >> +static const RegisterSet > >> +g_reg_sets[k_num_register_sets] = > >> +{ > >> + { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums }, > >> + { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums } > >> +}; > >> + > >> +// Computes the offset of the given GPR in the user data area. > >> +#define GPR_OFFSET(regname) \ > >> + (offsetof(RegisterContextLinux_i386::UserArea, regs) + \ > >> + offsetof(RegisterContextLinux_i386::GPR, regname)) > >> + > >> +// Computes the offset of the given FPR in the user data area. > >> +#define FPR_OFFSET(regname) \ > >> + (offsetof(RegisterContextLinux_i386::UserArea, i387) + \ > >> + offsetof(RegisterContextLinux_i386::FPU, regname)) > >> + > >> +// Number of bytes needed to represent a GPR. > >> +#define GPR_SIZE(reg) sizeof(((RegisterContextLinux_i386::GPR*)NULL)->reg) > >> + > >> +// Number of bytes needed to represent a FPR. > >> +#define FPR_SIZE(reg) sizeof(((RegisterContextLinux_i386::FPU*)NULL)->reg) > >> + > >> +// Number of bytes needed to represent the i'th FP register. > >> +#define FP_SIZE sizeof(((RegisterContextLinux_i386::MMSReg*)NULL)->bytes) > >> + > >> +// Number of bytes needed to represent an XMM register. > >> +#define XMM_SIZE sizeof(RegisterContextLinux_i386::XMMReg) > >> + > >> +#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ > >> + { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \ > >> + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg } } > >> + > >> +#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \ > >> + { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ > >> + eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg } } > >> + > >> +#define DEFINE_FP(reg, i) \ > >> + { #reg#i, NULL, FP_SIZE, FPR_OFFSET(reg[i]), eEncodingVector, \ > >> + eFormatVectorOfUInt8, \ > >> + { dwarf_##reg##i, dwarf_##reg##i, \ > >> + LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i } } > >> + > >> +#define DEFINE_XMM(reg, i) \ > >> + { #reg#i, NULL, XMM_SIZE, FPR_OFFSET(reg[i]), eEncodingVector, \ > >> + eFormatVectorOfUInt8, \ > >> + { dwarf_##reg##i, dwarf_##reg##i, \ > >> + LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i } } > >> + > >> +static RegisterInfo > >> +g_register_infos[k_num_registers] = > >> +{ > >> + // General purpose registers. > >> + DEFINE_GPR(eax, NULL, gcc_eax, dwarf_eax, LLDB_INVALID_REGNUM, gdb_eax), > >> + DEFINE_GPR(ebx, NULL, gcc_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, gdb_ebx), > >> + DEFINE_GPR(ecx, NULL, gcc_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, gdb_ecx), > >> + DEFINE_GPR(edx, NULL, gcc_edx, dwarf_edx, LLDB_INVALID_REGNUM, gdb_edx), > >> + DEFINE_GPR(edi, NULL, gcc_edi, dwarf_edi, LLDB_INVALID_REGNUM, gdb_edi), > >> + DEFINE_GPR(esi, NULL, gcc_esi, dwarf_esi, LLDB_INVALID_REGNUM, gdb_esi), > >> + DEFINE_GPR(ebp, "fp", gcc_ebp, dwarf_ebp, LLDB_INVALID_REGNUM, gdb_ebp), > >> + DEFINE_GPR(esp, "sp", gcc_esp, dwarf_esp, LLDB_INVALID_REGNUM, gdb_esp), > >> + DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ss), > >> + DEFINE_GPR(eflags, "flags", gcc_eflags, dwarf_eflags, LLDB_INVALID_REGNUM, gdb_eflags), > >> + DEFINE_GPR(eip, "pc", gcc_eip, dwarf_eip, LLDB_INVALID_REGNUM, gdb_eip), > >> + DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_cs), > >> + DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ds), > >> + DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_es), > >> + DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fs), > >> + DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gs), > >> + > >> + // Floating point registers. > >> + DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fcw), > >> + DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fsw), > >> + DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftw), > >> + DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop), > >> + DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ip), > >> + DEFINE_FPR(cs, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs), > >> + DEFINE_FPR(foo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_dp), > >> + DEFINE_FPR(fos, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds), > >> + DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_mxcsr), > >> + > >> + DEFINE_FP(stmm, 0), > >> + DEFINE_FP(stmm, 1), > >> + DEFINE_FP(stmm, 2), > >> + DEFINE_FP(stmm, 3), > >> + DEFINE_FP(stmm, 4), > >> + DEFINE_FP(stmm, 5), > >> + DEFINE_FP(stmm, 6), > >> + DEFINE_FP(stmm, 7), > >> + > >> + // XMM registers > >> + DEFINE_XMM(xmm, 0), > >> + DEFINE_XMM(xmm, 1), > >> + DEFINE_XMM(xmm, 2), > >> + DEFINE_XMM(xmm, 3), > >> + DEFINE_XMM(xmm, 4), > >> + DEFINE_XMM(xmm, 5), > >> + DEFINE_XMM(xmm, 6), > >> + DEFINE_XMM(xmm, 7), > >> + > >> +}; > >> + > >> +static unsigned GetRegOffset(unsigned reg) > >> +{ > >> + assert(reg < k_num_registers && "Invalid register number."); > >> + return g_register_infos[reg].byte_offset; > >> +} > >> + > >> +static unsigned GetRegSize(unsigned reg) > >> +{ > >> + assert(reg < k_num_registers && "Invalid register number."); > >> + return g_register_infos[reg].byte_size; > >> +} > >> + > >> +static bool IsGPR(unsigned reg) > >> +{ > >> + return reg <= k_last_gpr; // GPR's come first. > >> +} > >> + > >> +static bool IsFPR(unsigned reg) > >> +{ > >> + return (k_first_fpr <= reg && reg <= k_last_fpr); > >> +} > >> + > >> + > >> +RegisterContextLinux_i386::RegisterContextLinux_i386(Thread &thread, > >> + uint32_t concrete_frame_idx) > >> + : RegisterContextLinux(thread, concrete_frame_idx) > >> +{ > >> +} > >> + > >> +RegisterContextLinux_i386::~RegisterContextLinux_i386() > >> +{ > >> +} > >> + > >> +ProcessMonitor & > >> +RegisterContextLinux_i386::GetMonitor() > >> +{ > >> + ProcessLinux *process = static_cast(CalculateProcess()); > >> + return process->GetMonitor(); > >> +} > >> + > >> +void > >> +RegisterContextLinux_i386::Invalidate() > >> +{ > >> +} > >> + > >> +void > >> +RegisterContextLinux_i386::InvalidateAllRegisters() > >> +{ > >> +} > >> + > >> +size_t > >> +RegisterContextLinux_i386::GetRegisterCount() > >> +{ > >> + return k_num_registers; > >> +} > >> + > >> +const RegisterInfo * > >> +RegisterContextLinux_i386::GetRegisterInfoAtIndex(uint32_t reg) > >> +{ > >> + if (reg < k_num_registers) > >> + return &g_register_infos[reg]; > >> + else > >> + return NULL; > >> +} > >> + > >> +size_t > >> +RegisterContextLinux_i386::GetRegisterSetCount() > >> +{ > >> + return k_num_register_sets; > >> +} > >> + > >> +const RegisterSet * > >> +RegisterContextLinux_i386::GetRegisterSet(uint32_t set) > >> +{ > >> + if (set < k_num_register_sets) > >> + return &g_reg_sets[set]; > >> + else > >> + return NULL; > >> +} > >> + > >> +bool > >> +RegisterContextLinux_i386::ReadRegisterValue(uint32_t reg, > >> + Scalar &value) > >> +{ > >> + ProcessMonitor &monitor = GetMonitor(); > >> + return monitor.ReadRegisterValue(GetRegOffset(reg), value); > >> +} > >> + > >> +bool > >> +RegisterContextLinux_i386::ReadRegisterBytes(uint32_t reg, > >> + DataExtractor &data) > >> +{ > >> + uint8_t *buf = reinterpret_cast(&user); > >> + bool status; > >> + > >> + if (IsGPR(reg)) > >> + status = ReadGPR(); > >> + else if (IsFPR(reg)) > >> + status = ReadFPR(); > >> + else > >> + { > >> + assert(false && "invalid register number"); > >> + status = false; > >> + } > >> + > >> + if (status) > >> + data.SetData(buf + GetRegOffset(reg), GetRegSize(reg), lldb::endian::InlHostByteOrder()); > >> + > >> + return status; > >> +} > >> + > >> +bool > >> +RegisterContextLinux_i386::ReadAllRegisterValues(DataBufferSP &data_sp) > >> +{ > >> + return false; > >> +} > >> + > >> +bool > >> +RegisterContextLinux_i386::WriteRegisterValue(uint32_t reg, > >> + const Scalar &value) > >> +{ > >> + ProcessMonitor &monitor = GetMonitor(); > >> + return monitor.WriteRegisterValue(GetRegOffset(reg), value); > >> +} > >> + > >> +bool > >> +RegisterContextLinux_i386::WriteRegisterBytes(uint32_t reg, > >> + DataExtractor &data, > >> + uint32_t data_offset) > >> +{ > >> + return false; > >> +} > >> + > >> +bool > >> +RegisterContextLinux_i386::WriteAllRegisterValues(const DataBufferSP &data) > >> +{ > >> + return false; > >> +} > >> + > >> +bool > >> +RegisterContextLinux_i386::UpdateAfterBreakpoint() > >> +{ > >> + // PC points one byte past the int3 responsible for the breakpoint. > >> + lldb::addr_t pc; > >> + > >> + if ((pc = GetPC()) == LLDB_INVALID_ADDRESS) > >> + return false; > >> + > >> + SetPC(pc - 1); > >> + return true; > >> +} > >> + > >> +uint32_t > >> +RegisterContextLinux_i386::ConvertRegisterKindToRegisterNumber(uint32_t kind, > >> + uint32_t num) > >> +{ > >> + if (kind == eRegisterKindGeneric) > >> + { > >> + switch (num) > >> + { > >> + case LLDB_REGNUM_GENERIC_PC: return gpr_eip; > >> + case LLDB_REGNUM_GENERIC_SP: return gpr_esp; > >> + case LLDB_REGNUM_GENERIC_FP: return gpr_ebp; > >> + case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags; > >> + case LLDB_REGNUM_GENERIC_RA: > >> + default: > >> + return LLDB_INVALID_REGNUM; > >> + } > >> + } > >> + > >> + if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF) > >> + { > >> + switch (num) > >> + { > >> + case dwarf_eax: return gpr_eax; > >> + case dwarf_edx: return gpr_edx; > >> + case dwarf_ecx: return gpr_ecx; > >> + case dwarf_ebx: return gpr_ebx; > >> + case dwarf_esi: return gpr_esi; > >> + case dwarf_edi: return gpr_edi; > >> + case dwarf_ebp: return gpr_ebp; > >> + case dwarf_esp: return gpr_esp; > >> + case dwarf_eip: return gpr_eip; > >> + case dwarf_xmm0: return fpu_xmm0; > >> + case dwarf_xmm1: return fpu_xmm1; > >> + case dwarf_xmm2: return fpu_xmm2; > >> + case dwarf_xmm3: return fpu_xmm3; > >> + case dwarf_xmm4: return fpu_xmm4; > >> + case dwarf_xmm5: return fpu_xmm5; > >> + case dwarf_xmm6: return fpu_xmm6; > >> + case dwarf_xmm7: return fpu_xmm7; > >> + case dwarf_stmm0: return fpu_stmm0; > >> + case dwarf_stmm1: return fpu_stmm1; > >> + case dwarf_stmm2: return fpu_stmm2; > >> + case dwarf_stmm3: return fpu_stmm3; > >> + case dwarf_stmm4: return fpu_stmm4; > >> + case dwarf_stmm5: return fpu_stmm5; > >> + case dwarf_stmm6: return fpu_stmm6; > >> + case dwarf_stmm7: return fpu_stmm7; > >> + default: > >> + return LLDB_INVALID_REGNUM; > >> + } > >> + } > >> + > >> + if (kind == eRegisterKindGDB) > >> + { > >> + switch (num) > >> + { > >> + case gdb_eax : return gpr_eax; > >> + case gdb_ebx : return gpr_ebx; > >> + case gdb_ecx : return gpr_ecx; > >> + case gdb_edx : return gpr_edx; > >> + case gdb_esi : return gpr_esi; > >> + case gdb_edi : return gpr_edi; > >> + case gdb_ebp : return gpr_ebp; > >> + case gdb_esp : return gpr_esp; > >> + case gdb_eip : return gpr_eip; > >> + case gdb_eflags : return gpr_eflags; > >> + case gdb_cs : return gpr_cs; > >> + case gdb_ss : return gpr_ss; > >> + case gdb_ds : return gpr_ds; > >> + case gdb_es : return gpr_es; > >> + case gdb_fs : return gpr_fs; > >> + case gdb_gs : return gpr_gs; > >> + case gdb_stmm0 : return fpu_stmm0; > >> + case gdb_stmm1 : return fpu_stmm1; > >> + case gdb_stmm2 : return fpu_stmm2; > >> + case gdb_stmm3 : return fpu_stmm3; > >> + case gdb_stmm4 : return fpu_stmm4; > >> + case gdb_stmm5 : return fpu_stmm5; > >> + case gdb_stmm6 : return fpu_stmm6; > >> + case gdb_stmm7 : return fpu_stmm7; > >> + case gdb_fcw : return fpu_fcw; > >> + case gdb_fsw : return fpu_fsw; > >> + case gdb_ftw : return fpu_ftw; > >> + case gdb_fpu_cs : return fpu_cs; > >> + case gdb_ip : return fpu_ip; > >> + case gdb_fpu_ds : return fpu_fos; > >> + case gdb_dp : return fpu_foo; > >> + case gdb_fop : return fpu_fop; > >> + case gdb_xmm0 : return fpu_xmm0; > >> + case gdb_xmm1 : return fpu_xmm1; > >> + case gdb_xmm2 : return fpu_xmm2; > >> + case gdb_xmm3 : return fpu_xmm3; > >> + case gdb_xmm4 : return fpu_xmm4; > >> + case gdb_xmm5 : return fpu_xmm5; > >> + case gdb_xmm6 : return fpu_xmm6; > >> + case gdb_xmm7 : return fpu_xmm7; > >> + case gdb_mxcsr : return fpu_mxcsr; > >> + default: > >> + return LLDB_INVALID_REGNUM; > >> + } > >> + } > >> + else if (kind == eRegisterKindLLDB) > >> + { > >> + return num; > >> + } > >> + > >> + return LLDB_INVALID_REGNUM; > >> +} > >> + > >> +bool > >> +RegisterContextLinux_i386::HardwareSingleStep(bool enable) > >> +{ > >> + enum { TRACE_BIT = 0x100 }; > >> + uint64_t eflags; > >> + > >> + if ((eflags = ReadRegisterAsUnsigned(gpr_eflags, -1UL)) == -1UL) > >> + return false; > >> + > >> + if (enable) > >> + { > >> + if (eflags & TRACE_BIT) > >> + return true; > >> + > >> + eflags |= TRACE_BIT; > >> + } > >> + else > >> + { > >> + if (!(eflags & TRACE_BIT)) > >> + return false; > >> + > >> + eflags &= ~TRACE_BIT; > >> + } > >> + > >> + return WriteRegisterFromUnsigned(gpr_eflags, eflags); > >> +} > >> + > >> +bool > >> +RegisterContextLinux_i386::ReadGPR() > >> +{ > >> + ProcessMonitor &monitor = GetMonitor(); > >> + return monitor.ReadGPR(&user.regs); > >> +} > >> + > >> +bool > >> +RegisterContextLinux_i386::ReadFPR() > >> +{ > >> + ProcessMonitor &monitor = GetMonitor(); > >> + return monitor.ReadFPR(&user.i387); > >> +} > >> diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_i386.h b/source/Plugins/Process/Linux/RegisterContextLinux_i386.h > >> new file mode 100644 > >> index 0000000..30b3d70 > >> --- /dev/null > >> +++ b/source/Plugins/Process/Linux/RegisterContextLinux_i386.h > >> @@ -0,0 +1,148 @@ > >> +//===-- RegisterContextLinux_i386.h ------------------------------*- C++ -*-===// > >> +// > >> +// The LLVM Compiler Infrastructure > >> +// > >> +// This file is distributed under the University of Illinois Open Source > >> +// License. See LICENSE.TXT for details. > >> +// > >> +//===----------------------------------------------------------------------===// > >> + > >> +#ifndef liblldb_RegisterContextLinux_i386_h_ > >> +#define liblldb_RegisterContextLinux_i386_h_ > >> + > >> +// C Includes > >> +// C++ Includes > >> +// Other libraries and framework includes > >> +// Project includes > >> +#include "RegisterContextLinux.h" > >> + > >> +class RegisterContextLinux_i386 : public RegisterContextLinux > >> +{ > >> +public: > >> + RegisterContextLinux_i386(lldb_private::Thread &thread, > >> + uint32_t concreate_frame_idx); > >> + > >> + ~RegisterContextLinux_i386(); > >> + > >> + void > >> + Invalidate(); > >> + > >> + void > >> + InvalidateAllRegisters(); > >> + > >> + size_t > >> + GetRegisterCount(); > >> + > >> + const lldb::RegisterInfo * > >> + GetRegisterInfoAtIndex(uint32_t reg); > >> + > >> + size_t > >> + GetRegisterSetCount(); > >> + > >> + const lldb::RegisterSet * > >> + GetRegisterSet(uint32_t set); > >> + > >> + bool > >> + ReadRegisterValue(uint32_t reg, lldb_private::Scalar &value); > >> + > >> + bool > >> + ReadRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data); > >> + > >> + bool > >> + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); > >> + > >> + bool > >> + WriteRegisterValue(uint32_t reg, const lldb_private::Scalar &value); > >> + > >> + bool > >> + WriteRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data, > >> + uint32_t data_offset = 0); > >> + > >> + bool > >> + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); > >> + > >> + uint32_t > >> + ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num); > >> + > >> + bool > >> + HardwareSingleStep(bool enable); > >> + > >> + bool > >> + UpdateAfterBreakpoint(); > >> + > >> + struct GPR > >> + { > >> + uint32_t ebx; > >> + uint32_t ecx; > >> + uint32_t edx; > >> + uint32_t esi; > >> + uint32_t edi; > >> + uint32_t ebp; > >> + uint32_t eax; > >> + uint32_t ds; > >> + uint32_t es; > >> + uint32_t fs; > >> + uint32_t gs; > >> + uint32_t orig_ax; > >> + uint32_t eip; > >> + uint32_t cs; > >> + uint32_t eflags; > >> + uint32_t esp; > >> + uint32_t ss; > >> + }; > >> + > >> + struct MMSReg > >> + { > >> + uint8_t bytes[8]; > >> + }; > >> + > >> + struct XMMReg > >> + { > >> + uint8_t bytes[16]; > >> + }; > >> + > >> + struct FPU > >> + { > >> + uint16_t fcw; > >> + uint16_t fsw; > >> + uint16_t ftw; > >> + uint16_t fop; > >> + uint32_t ip; > >> + uint32_t cs; > >> + uint32_t foo; > >> + uint32_t fos; > >> + uint32_t mxcsr; > >> + uint32_t reserved; > >> + MMSReg stmm[8]; > >> + XMMReg xmm[8]; > >> + uint32_t pad[56]; > >> + }; > >> + > >> + struct UserArea > >> + { > >> + GPR regs; // General purpose registers. > >> + int32_t fpvalid; // True if FPU is being used. > >> + FPU i387; // FPU registers. > >> + uint32_t tsize; // Text segment size. > >> + uint32_t dsize; // Data segment size. > >> + uint32_t ssize; // Stack segment size. > >> + uint32_t start_code; // VM address of text. > >> + uint32_t start_stack; // VM address of stack bottom (top in rsp). > >> + int32_t signal; // Signal causing core dump. > >> + int32_t reserved; // Unused. > >> + uint32_t ar0; // Location of GPR's. > >> + FPU* fpstate; // Location of FPR's. > >> + uint32_t magic; // Identifier for core dumps. > >> + char u_comm[32]; // Command causing core dump. > >> + uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7). > >> + }; > >> +private: > >> + UserArea user; > >> + > >> + ProcessMonitor &GetMonitor(); > >> + > >> + bool ReadGPR(); > >> + bool ReadFPR(); > >> +}; > >> + > >> +#endif // #ifndef liblldb_RegisterContextLinux_i386_h_ > > > > > > -- > > steve > > > -- steve From ctice at apple.com Mon Feb 28 17:15:24 2011 From: ctice at apple.com (Caroline Tice) Date: Mon, 28 Feb 2011 23:15:24 -0000 Subject: [Lldb-commits] [lldb] r126709 - /lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp Message-ID: <20110228231524.565DF2A6C12C@llvm.org> Author: ctice Date: Mon Feb 28 17:15:24 2011 New Revision: 126709 URL: http://llvm.org/viewvc/llvm-project?rev=126709&view=rev Log: Add code to emulate LDRH (literal) Arm instruction. Modified: lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp Modified: lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp?rev=126709&r1=126708&r2=126709&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp (original) +++ lldb/trunk/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp Mon Feb 28 17:15:24 2011 @@ -6024,6 +6024,117 @@ return true; } +// LDRH (literal) caculates an address from the PC value and an immediate offset, loads a halfword from memory, +// zero-extends it to form a 32-bit word, and writes it to a register. +bool +EmulateInstructionARM::EmulateLDRHLiteral (ARMEncoding encoding) +{ +#if 0 + if ConditionPassed() then + EncodingSpecificOperations(); NullCheckIfThumbEE(15); + base = Align(PC,4); + address = if add then (base + imm32) else (base - imm32); + data = MemU[address,2]; + if UnalignedSupport() || address<0> = ???0??? then + R[t] = ZeroExtend(data, 32); + else // Can only apply before ARMv7 + R[t] = bits(32) UNKNOWN; +#endif + + + bool success = false; + const uint32_t opcode = OpcodeAsUnsigned (&success); + if (!success) + return false; + + if (ConditionPassed()) + { + uint32_t t; + uint32_t imm32; + bool add; + + // EncodingSpecificOperations(); NullCheckIfThumbEE(15); + switch (encoding) + { + case eEncodingT1: + // if Rt == ???1111??? then SEE "Unallocated memory hints"; + // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == ???1???); + t = Bits32 (opcode, 15, 12); + imm32 = Bits32 (opcode, 11, 0); + add = BitIsSet (opcode, 23); + + // if t == 13 then UNPREDICTABLE; + if (t == 13) + return false; + + break; + + case eEncodingA1: + { + uint32_t imm4H = Bits32 (opcode, 11, 8); + uint32_t imm4L = Bits32 (opcode, 3, 0); + + // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == ???1???); + t = Bits32 (opcode, 15, 12); + imm32 = (imm4H << 4) & imm4L; + add = BitIsSet (opcode, 23); + + // if t == 15 then UNPREDICTABLE; + if (t == 15) + return false; + break; + } + + default: + return false; + } + + // base = Align(PC,4); + uint64_t pc_value = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); + if (!success) + return false; + + addr_t base = AlignPC (pc_value); + addr_t address; + + // address = if add then (base + imm32) else (base - imm32); + if (add) + address = base + imm32; + else + address = base - imm32; + + // data = MemU[address,2]; + Register base_reg; + base_reg.SetRegister (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + + EmulateInstruction::Context context; + context.type = eContextRegisterLoad; + context.SetRegisterPlusOffset (base_reg, address - base); + + uint64_t data = MemURead (context, address, 2, 0, &success); + if (!success) + return false; + + + // if UnalignedSupport() || address<0> = ???0??? then + if (UnalignedSupport () || BitIsClear (address, 0)) + { + // R[t] = ZeroExtend(data, 32); + context.type = eContextRegisterLoad; + context.SetRegisterPlusOffset (base_reg, address - base); + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) + return false; + + } + else // Can only apply before ARMv7 + { + // R[t] = bits(32) UNKNOWN; + WriteBits32Unknown (t); + } + } + return true; +} + // Bitwise Exclusive OR (immediate) performs a bitwise exclusive OR of a register value and an immediate value, // and writes the result to the destination register. It can optionally update the condition flags based on // the result. @@ -7396,6 +7507,7 @@ { 0x0e500010, 0x06100000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDRRegister, "ldr [ +/- {}] {!}" }, { 0x0e5f0000, 0x045f0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb , [...]"}, { 0xfe500010, 0x06500000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb , [,+/-{, }]{!}" }, + { 0x0e5f00f0, 0x005f00b0, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh ,