Skip to content

Commit 17f383d

Browse files
author
Zachary Turner
committedNov 20, 2014
[ProcessWindows] Implement a RegisterContextWindows for x86.
This implements the skeleton of a RegisterContext for Windows. In particular, this implements support only for x86 general purpose registers. After this patch, LLDB on Windows can perform basic debugging operations in a single-threaded inferior process (breakpoint, register inspection, frame select, unwinding, etc). Differential Revision: http://reviews.llvm.org/D6322 Reviewed by: Greg Clayton llvm-svn: 222474
1 parent e35b07a commit 17f383d

6 files changed

+460
-11
lines changed
 

‎lldb/source/Plugins/Process/Windows/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ add_lldb_library(lldbPluginProcessWindows
77
DebuggerThread.cpp
88
LocalDebugDelegate.cpp
99
ProcessWindows.cpp
10+
RegisterContextWindows_x86.cpp
1011
TargetThreadWindows.cpp
1112
)
1213

‎lldb/source/Plugins/Process/Windows/ProcessWindows.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ ProcessWindows::DoDestroy()
254254
void
255255
ProcessWindows::RefreshStateAfterStop()
256256
{
257+
m_thread_list.RefreshStateAfterStop();
257258
}
258259

259260
bool
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
//===-- RegisterContextWindows_x86.h ----------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "lldb/lldb-private-types.h"
11+
#include "lldb/Core/DataBufferHeap.h"
12+
#include "lldb/Core/Error.h"
13+
#include "lldb/Core/RegisterValue.h"
14+
#include "lldb/Host/windows/HostThreadWindows.h"
15+
#include "lldb/Host/windows/windows.h"
16+
17+
#include "lldb-x86-register-enums.h"
18+
#include "RegisterContext_x86.h"
19+
#include "RegisterContextWindows_x86.h"
20+
#include "TargetThreadWindows.h"
21+
22+
#include "llvm/ADT/STLExtras.h"
23+
24+
using namespace lldb;
25+
using namespace lldb_private;
26+
27+
#define DEFINE_GPR32(reg, offset, generic_reg) \
28+
{ \
29+
#reg, nullptr, 4, offset, eEncodingUint, eFormatHexUppercase, \
30+
{gcc_##reg##_i386, dwarf_##reg##_i386, generic_reg, gdb_##reg##_i386, gpr_##reg##_i386 }, nullptr, nullptr \
31+
}
32+
33+
#define GPR_REGNUM(reg) gpr_##reg##_i386
34+
35+
// For now we're only supporting general purpose registers. Unfortunately we have to maintain
36+
// parallel arrays since that's how the RegisterContext interface expects things to be returned.
37+
// We might be able to fix this by initializing these arrays at runtime during the construction of
38+
// the RegisterContext by using helper functions that can update multiple arrays, register sets,
39+
// etc all at once through a more easily understandable interface.
40+
41+
RegisterInfo g_register_infos[] = {DEFINE_GPR32(eax, offsetof(CONTEXT, Eax), LLDB_INVALID_REGNUM),
42+
DEFINE_GPR32(ebx, offsetof(CONTEXT, Ebx), LLDB_INVALID_REGNUM),
43+
DEFINE_GPR32(ecx, offsetof(CONTEXT, Ecx), LLDB_INVALID_REGNUM),
44+
DEFINE_GPR32(edx, offsetof(CONTEXT, Edx), LLDB_INVALID_REGNUM),
45+
DEFINE_GPR32(edi, offsetof(CONTEXT, Edi), LLDB_INVALID_REGNUM),
46+
DEFINE_GPR32(esi, offsetof(CONTEXT, Esi), LLDB_INVALID_REGNUM),
47+
DEFINE_GPR32(ebp, offsetof(CONTEXT, Ebp), LLDB_REGNUM_GENERIC_FP),
48+
DEFINE_GPR32(esp, offsetof(CONTEXT, Esp), LLDB_REGNUM_GENERIC_SP),
49+
DEFINE_GPR32(eip, offsetof(CONTEXT, Eip), LLDB_REGNUM_GENERIC_PC),
50+
DEFINE_GPR32(eflags, offsetof(CONTEXT, EFlags), LLDB_REGNUM_GENERIC_FLAGS)};
51+
52+
uint32_t g_gpr_regnums[] = {
53+
GPR_REGNUM(eax), GPR_REGNUM(ebx), GPR_REGNUM(ecx), GPR_REGNUM(edx), GPR_REGNUM(edi),
54+
GPR_REGNUM(esi), GPR_REGNUM(ebp), GPR_REGNUM(esp), GPR_REGNUM(eip), GPR_REGNUM(eflags),
55+
};
56+
57+
RegisterSet g_register_sets[] = {{"General Purpose Registers", "gpr", llvm::array_lengthof(g_register_infos), g_gpr_regnums}};
58+
59+
//------------------------------------------------------------------
60+
// Constructors and Destructors
61+
//------------------------------------------------------------------
62+
RegisterContextWindows_x86::RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx)
63+
: RegisterContext(thread, concrete_frame_idx)
64+
, m_context_valid(false)
65+
, m_cached_context(new DataBufferHeap(sizeof(CONTEXT), 0))
66+
{
67+
}
68+
69+
RegisterContextWindows_x86::~RegisterContextWindows_x86()
70+
{
71+
}
72+
73+
void
74+
RegisterContextWindows_x86::InvalidateAllRegisters()
75+
{
76+
m_context_valid = false;
77+
}
78+
79+
size_t
80+
RegisterContextWindows_x86::GetRegisterCount()
81+
{
82+
return llvm::array_lengthof(g_register_infos);
83+
}
84+
85+
const RegisterInfo *
86+
RegisterContextWindows_x86::GetRegisterInfoAtIndex(size_t reg)
87+
{
88+
return &g_register_infos[reg];
89+
}
90+
91+
size_t
92+
RegisterContextWindows_x86::GetRegisterSetCount()
93+
{
94+
return llvm::array_lengthof(g_register_sets);
95+
}
96+
97+
const RegisterSet *
98+
RegisterContextWindows_x86::GetRegisterSet(size_t reg_set)
99+
{
100+
return &g_register_sets[reg_set];
101+
}
102+
103+
bool
104+
RegisterContextWindows_x86::ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value)
105+
{
106+
// For now we're reading the value of every register, and then returning the one that was
107+
// requested. We should be smarter about this in the future.
108+
if (!CacheAllRegisterValues())
109+
return false;
110+
111+
CONTEXT *context = GetSystemContext();
112+
switch (reg_info->kinds[eRegisterKindLLDB])
113+
{
114+
case gpr_eax_i386:
115+
reg_value.SetUInt32(context->Eax);
116+
break;
117+
case gpr_ebx_i386:
118+
reg_value.SetUInt32(context->Ebx);
119+
break;
120+
case gpr_ecx_i386:
121+
reg_value.SetUInt32(context->Ecx);
122+
break;
123+
case gpr_edx_i386:
124+
reg_value.SetUInt32(context->Edx);
125+
break;
126+
case gpr_edi_i386:
127+
reg_value.SetUInt32(context->Edi);
128+
break;
129+
case gpr_esi_i386:
130+
reg_value.SetUInt32(context->Esi);
131+
break;
132+
case gpr_ebp_i386:
133+
reg_value.SetUInt32(context->Ebp);
134+
break;
135+
case gpr_esp_i386:
136+
reg_value.SetUInt32(context->Esp);
137+
break;
138+
case gpr_eip_i386:
139+
reg_value.SetUInt32(context->Eip);
140+
break;
141+
case gpr_eflags_i386:
142+
reg_value.SetUInt32(context->EFlags);
143+
break;
144+
}
145+
return true;
146+
}
147+
148+
bool
149+
RegisterContextWindows_x86::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value)
150+
{
151+
// Since we cannot only write a single register value to the inferior, we need to make sure
152+
// our cached copy of the register values are fresh. Otherwise when writing EAX, for example,
153+
// we may also overwrite some other register with a stale value.
154+
if (!CacheAllRegisterValues())
155+
return false;
156+
157+
CONTEXT *context = GetSystemContext();
158+
switch (reg_info->kinds[eRegisterKindLLDB])
159+
{
160+
case gpr_eax_i386:
161+
context->Eax = reg_value.GetAsUInt32();
162+
break;
163+
case gpr_ebx_i386:
164+
context->Ebx = reg_value.GetAsUInt32();
165+
break;
166+
case gpr_ecx_i386:
167+
context->Ecx = reg_value.GetAsUInt32();
168+
break;
169+
case gpr_edx_i386:
170+
context->Edx = reg_value.GetAsUInt32();
171+
break;
172+
case gpr_edi_i386:
173+
context->Edi = reg_value.GetAsUInt32();
174+
break;
175+
case gpr_esi_i386:
176+
context->Esi = reg_value.GetAsUInt32();
177+
break;
178+
case gpr_ebp_i386:
179+
context->Ebp = reg_value.GetAsUInt32();
180+
break;
181+
case gpr_esp_i386:
182+
context->Esp = reg_value.GetAsUInt32();
183+
break;
184+
case gpr_eip_i386:
185+
context->Eip = reg_value.GetAsUInt32();
186+
break;
187+
case gpr_eflags_i386:
188+
context->EFlags = reg_value.GetAsUInt32();
189+
break;
190+
}
191+
192+
// Physically update the registers in the target process.
193+
TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
194+
return ::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), context);
195+
}
196+
197+
bool
198+
RegisterContextWindows_x86::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
199+
{
200+
if (!CacheAllRegisterValues())
201+
return false;
202+
203+
if (data_sp->GetByteSize() != m_cached_context->GetByteSize())
204+
return false;
205+
206+
// Write the OS's internal CONTEXT structure into the buffer.
207+
memcpy(data_sp->GetBytes(), m_cached_context->GetBytes(), data_sp->GetByteSize());
208+
return true;
209+
}
210+
211+
bool
212+
RegisterContextWindows_x86::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
213+
{
214+
// Since we're given every register value in the input buffer, we don't need to worry about
215+
// making sure our cached copy is valid and then overwriting the modified values before we
216+
// push the full update to the OS. We do however need to update the cached copy with the value
217+
// that we're pushing to the OS.
218+
if (data_sp->GetByteSize() != m_cached_context->GetByteSize())
219+
return false;
220+
221+
CONTEXT *context = GetSystemContext();
222+
TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
223+
224+
if (!::SetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), context))
225+
return false;
226+
227+
// Since the thread context was set successfully, update our cached copy.
228+
memcpy(m_cached_context->GetBytes(), data_sp->GetBytes(), data_sp->GetByteSize());
229+
return true;
230+
}
231+
232+
uint32_t
233+
RegisterContextWindows_x86::ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num)
234+
{
235+
const uint32_t num_regs = GetRegisterCount();
236+
237+
assert(kind < kNumRegisterKinds);
238+
for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
239+
{
240+
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx);
241+
242+
if (reg_info->kinds[kind] == num)
243+
return reg_idx;
244+
}
245+
246+
return LLDB_INVALID_REGNUM;
247+
}
248+
249+
//------------------------------------------------------------------
250+
// Subclasses can these functions if desired
251+
//------------------------------------------------------------------
252+
uint32_t
253+
RegisterContextWindows_x86::NumSupportedHardwareBreakpoints()
254+
{
255+
// Support for hardware breakpoints not yet implemented.
256+
return 0;
257+
}
258+
259+
uint32_t
260+
RegisterContextWindows_x86::SetHardwareBreakpoint(lldb::addr_t addr, size_t size)
261+
{
262+
return 0;
263+
}
264+
265+
bool
266+
RegisterContextWindows_x86::ClearHardwareBreakpoint(uint32_t hw_idx)
267+
{
268+
return false;
269+
}
270+
271+
uint32_t
272+
RegisterContextWindows_x86::NumSupportedHardwareWatchpoints()
273+
{
274+
// Support for hardware watchpoints not yet implemented.
275+
return 0;
276+
}
277+
278+
uint32_t
279+
RegisterContextWindows_x86::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write)
280+
{
281+
return 0;
282+
}
283+
284+
bool
285+
RegisterContextWindows_x86::ClearHardwareWatchpoint(uint32_t hw_index)
286+
{
287+
return false;
288+
}
289+
290+
bool
291+
RegisterContextWindows_x86::HardwareSingleStep(bool enable)
292+
{
293+
return false;
294+
}
295+
296+
CONTEXT *
297+
RegisterContextWindows_x86::GetSystemContext()
298+
{
299+
return reinterpret_cast<CONTEXT *>(m_cached_context->GetBytes());
300+
}
301+
302+
bool
303+
RegisterContextWindows_x86::CacheAllRegisterValues()
304+
{
305+
if (m_context_valid)
306+
return true;
307+
308+
CONTEXT *context = GetSystemContext();
309+
// Right now we just pull every single register, regardless of what register we're ultimately
310+
// going to read. We could be smarter about this, although it's not clear what the advantage
311+
// would be.
312+
context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
313+
TargetThreadWindows &wthread = static_cast<TargetThreadWindows &>(m_thread);
314+
if (!::GetThreadContext(wthread.GetHostThread().GetNativeThread().GetSystemHandle(), context))
315+
return false;
316+
m_context_valid = true;
317+
return true;
318+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//===-- RegisterContextWindows_x86.h ----------------------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef liblldb_RegisterContextWindows_x86_H_
11+
#define liblldb_RegisterContextWindows_x86_H_
12+
13+
#include "lldb/lldb-forward.h"
14+
#include "lldb/Target/RegisterContext.h"
15+
16+
namespace lldb_private
17+
{
18+
19+
class Thread;
20+
21+
class RegisterContextWindows_x86 : public lldb_private::RegisterContext
22+
{
23+
public:
24+
//------------------------------------------------------------------
25+
// Constructors and Destructors
26+
//------------------------------------------------------------------
27+
RegisterContextWindows_x86(Thread &thread, uint32_t concrete_frame_idx);
28+
29+
virtual ~RegisterContextWindows_x86();
30+
31+
//------------------------------------------------------------------
32+
// Subclasses must override these functions
33+
//------------------------------------------------------------------
34+
void InvalidateAllRegisters() override;
35+
36+
size_t GetRegisterCount() override;
37+
38+
const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
39+
40+
size_t GetRegisterSetCount() override;
41+
42+
const RegisterSet *GetRegisterSet(size_t reg_set) override;
43+
44+
bool ReadRegister(const RegisterInfo *reg_info, RegisterValue &reg_value) override;
45+
46+
bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue &reg_value) override;
47+
48+
bool ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override;
49+
50+
bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
51+
52+
uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) override;
53+
54+
//------------------------------------------------------------------
55+
// Subclasses can override these functions if desired
56+
//------------------------------------------------------------------
57+
uint32_t NumSupportedHardwareBreakpoints() override;
58+
59+
uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;
60+
61+
bool ClearHardwareBreakpoint(uint32_t hw_idx) override;
62+
63+
uint32_t NumSupportedHardwareWatchpoints() override;
64+
65+
uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, bool read, bool write) override;
66+
67+
bool ClearHardwareWatchpoint(uint32_t hw_index) override;
68+
69+
bool HardwareSingleStep(bool enable) override;
70+
71+
private:
72+
CONTEXT *GetSystemContext();
73+
74+
bool CacheAllRegisterValues();
75+
76+
lldb::DataBufferSP m_cached_context;
77+
bool m_context_valid;
78+
};
79+
}
80+
81+
#endif // #ifndef liblldb_RegisterContextPOSIX_x86_H_

‎lldb/source/Plugins/Process/Windows/TargetThreadWindows.cpp

+43-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@
77
//
88
//===----------------------------------------------------------------------===//
99

10-
#include "TargetThreadWindows.h"
11-
#include "ProcessWindows.h"
10+
#include "lldb/Host/HostInfo.h"
1211
#include "lldb/Host/HostNativeThreadBase.h"
1312
#include "lldb/Host/windows/HostThreadWindows.h"
1413
#include "lldb/Host/windows/windows.h"
14+
#include "lldb/Target/RegisterContext.h"
15+
16+
#include "TargetThreadWindows.h"
17+
#include "ProcessWindows.h"
18+
#include "RegisterContextWindows_x86.h"
19+
#include "UnwindLLDB.h"
1520

1621
using namespace lldb;
1722
using namespace lldb_private;
@@ -30,6 +35,7 @@ TargetThreadWindows::~TargetThreadWindows()
3035
void
3136
TargetThreadWindows::RefreshStateAfterStop()
3237
{
38+
GetRegisterContext()->InvalidateIfNeeded(false);
3339
}
3440

3541
void
@@ -45,19 +51,51 @@ TargetThreadWindows::DidStop()
4551
RegisterContextSP
4652
TargetThreadWindows::GetRegisterContext()
4753
{
48-
return RegisterContextSP();
54+
if (!m_reg_context_sp)
55+
m_reg_context_sp = CreateRegisterContextForFrameIndex(0);
56+
57+
return m_reg_context_sp;
4958
}
5059

5160
RegisterContextSP
5261
TargetThreadWindows::CreateRegisterContextForFrame(StackFrame *frame)
5362
{
54-
return RegisterContextSP();
63+
return CreateRegisterContextForFrameIndex(frame->GetConcreteFrameIndex());
64+
}
65+
66+
RegisterContextSP
67+
TargetThreadWindows::CreateRegisterContextForFrameIndex(uint32_t idx)
68+
{
69+
if (!m_reg_context_sp)
70+
{
71+
ArchSpec arch = HostInfo::GetArchitecture();
72+
switch (arch.GetMachine())
73+
{
74+
case llvm::Triple::x86:
75+
m_reg_context_sp.reset(new RegisterContextWindows_x86(*this, idx));
76+
break;
77+
default:
78+
// FIXME: Support x64 by creating a RegisterContextWindows_x86_64
79+
break;
80+
}
81+
}
82+
return m_reg_context_sp;
5583
}
5684

5785
bool
5886
TargetThreadWindows::CalculateStopInfo()
5987
{
60-
return false;
88+
SetStopInfo(m_stop_info_sp);
89+
return true;
90+
}
91+
92+
Unwind *
93+
TargetThreadWindows::GetUnwinder()
94+
{
95+
// FIXME: Implement an unwinder based on the Windows unwinder exposed through DIA SDK.
96+
if (m_unwinder_ap.get() == NULL)
97+
m_unwinder_ap.reset(new UnwindLLDB(*this));
98+
return m_unwinder_ap.get();
6199
}
62100

63101
bool

‎lldb/source/Plugins/Process/Windows/TargetThreadWindows.h

+16-6
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,26 @@ class TargetThreadWindows : public lldb_private::Thread
2828
TargetThreadWindows(ProcessWindows &process, const HostThread &thread);
2929
virtual ~TargetThreadWindows();
3030

31-
virtual void RefreshStateAfterStop() override;
32-
virtual void WillResume(lldb::StateType resume_state) override;
33-
virtual void DidStop() override;
34-
virtual lldb::RegisterContextSP GetRegisterContext() override;
35-
virtual lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame) override;
36-
virtual bool CalculateStopInfo() override;
31+
// lldb_private::Thread overrides
32+
void RefreshStateAfterStop() override;
33+
void WillResume(lldb::StateType resume_state) override;
34+
void DidStop() override;
35+
lldb::RegisterContextSP GetRegisterContext() override;
36+
lldb::RegisterContextSP CreateRegisterContextForFrame(StackFrame *frame) override;
37+
bool CalculateStopInfo() override;
38+
Unwind *GetUnwinder() override;
3739

3840
bool DoResume();
3941

42+
HostThread
43+
GetHostThread() const
44+
{
45+
return m_host_thread;
46+
}
47+
4048
private:
49+
lldb::RegisterContextSP CreateRegisterContextForFrameIndex(uint32_t idx);
50+
4151
lldb::StackFrameUP m_stack_frame;
4252

4353
HostThread m_host_thread;

0 commit comments

Comments
 (0)
Please sign in to comment.