Skip to content

Commit 4bb6244

Browse files
[ThreadPlan] fix exec on Linux
1 parent d368128 commit 4bb6244

26 files changed

+158
-41
lines changed

lldb/include/lldb/Target/Process.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2014,8 +2014,17 @@ class Process : public std::enable_shared_from_this<Process>,
20142014
virtual Status DisableWatchpoint(Watchpoint *wp, bool notify = true);
20152015

20162016
// Thread Queries
2017-
virtual bool UpdateThreadList(ThreadList &old_thread_list,
2018-
ThreadList &new_thread_list) = 0;
2017+
2018+
/// Update the thread list.
2019+
///
2020+
/// This method performs some general clean up before invoking
2021+
/// \a DoUpdateThreadList, which should be implemented by each
2022+
/// process plugin.
2023+
///
2024+
/// \return
2025+
/// \b true if the new thread list could be generated, \b false otherwise.
2026+
bool UpdateThreadList(ThreadList &old_thread_list,
2027+
ThreadList &new_thread_list);
20192028

20202029
void UpdateThreadListIfNeeded();
20212030

@@ -2514,6 +2523,15 @@ void PruneThreadPlans();
25142523
bool trap_exceptions = false);
25152524

25162525
protected:
2526+
/// Update the thread list following process plug-in's specific logic.
2527+
///
2528+
/// This method should only be invoked by \a UpdateThreadList.
2529+
///
2530+
/// \return
2531+
/// \b true if the new thread list could be generated, \b false otherwise.
2532+
virtual bool DoUpdateThreadList(ThreadList &old_thread_list,
2533+
ThreadList &new_thread_list) = 0;
2534+
25172535
/// Actually do the reading of memory from a process.
25182536
///
25192537
/// Subclasses must override this function and can return fewer bytes than

lldb/include/lldb/Target/ProcessTrace.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ class ProcessTrace : public PostMortemProcess {
7171
protected:
7272
void Clear();
7373

74-
bool UpdateThreadList(ThreadList &old_thread_list,
75-
ThreadList &new_thread_list) override;
74+
bool DoUpdateThreadList(ThreadList &old_thread_list,
75+
ThreadList &new_thread_list) override;
7676

7777
private:
7878
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,

lldb/include/lldb/Target/ThreadPlan.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,12 @@ class ThreadPlan : public std::enable_shared_from_this<ThreadPlan>,
325325

326326
const Target &GetTarget() const;
327327

328+
/// Clear the Thread* cache.
329+
///
330+
/// This is useful in situations like when a new Thread list is being
331+
/// generated.
332+
void ClearThreadCache();
333+
328334
/// Print a description of this thread to the stream \a s.
329335
/// \a thread. Don't expect that the result of GetThread is valid in
330336
/// the description method. This might get called when the underlying

lldb/include/lldb/Target/ThreadPlanStack.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ class ThreadPlanStack {
9595

9696
void WillResume();
9797

98+
/// Clear the Thread* cache that each ThreadPlan contains.
99+
///
100+
/// This is useful in situations like when a new Thread list is being
101+
/// generated.
102+
void ClearThreadCache();
103+
98104
private:
99105
const PlanStack &GetStackOfKind(ThreadPlanStack::StackKind kind) const;
100106

@@ -145,6 +151,15 @@ class ThreadPlanStackMap {
145151
return &result->second;
146152
}
147153

154+
/// Clear the Thread* cache that each ThreadPlan contains.
155+
///
156+
/// This is useful in situations like when a new Thread list is being
157+
/// generated.
158+
void ClearThreadCache() {
159+
for (auto &plan_list : m_plans_list)
160+
plan_list.second.ClearThreadCache();
161+
}
162+
148163
void Clear() {
149164
for (auto plan : m_plans_list)
150165
plan.second.ThreadDestroyed(nullptr);

lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ Status ProcessFreeBSD::DoResume() {
166166
return Status();
167167
}
168168

169-
bool ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list,
170-
ThreadList &new_thread_list) {
169+
bool ProcessFreeBSD::DoUpdateThreadList(ThreadList &old_thread_list,
170+
ThreadList &new_thread_list) {
171171
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
172172
LLDB_LOGF(log, "ProcessFreeBSD::%s (pid = %" PRIu64 ")", __FUNCTION__,
173173
GetID());

lldb/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ class ProcessFreeBSD : public lldb_private::Process {
118118

119119
virtual uint32_t UpdateThreadListIfNeeded();
120120

121-
bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
122-
lldb_private::ThreadList &new_thread_list) override;
121+
bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
122+
lldb_private::ThreadList &new_thread_list) override;
123123

124124
virtual lldb::ByteOrder GetByteOrder() const;
125125

lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,8 @@ lldb::ThreadSP ProcessKDP::GetKernelThread() {
508508
return thread_sp;
509509
}
510510

511-
bool ProcessKDP::UpdateThreadList(ThreadList &old_thread_list,
512-
ThreadList &new_thread_list) {
511+
bool ProcessKDP::DoUpdateThreadList(ThreadList &old_thread_list,
512+
ThreadList &new_thread_list) {
513513
// locker will keep a mutex locked until it goes out of scope
514514
Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_THREAD));
515515
LLDB_LOGV(log, "pid = {0}", GetID());

lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ class ProcessKDP : public lldb_private::Process {
158158

159159
void Clear();
160160

161-
bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
162-
lldb_private::ThreadList &new_thread_list) override;
161+
bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
162+
lldb_private::ThreadList &new_thread_list) override;
163163

164164
enum {
165165
eBroadcastBitAsyncContinue = (1 << 0),

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -510,8 +510,8 @@ bool ProcessWindows::CanDebug(lldb::TargetSP target_sp,
510510
return true;
511511
}
512512

513-
bool ProcessWindows::UpdateThreadList(ThreadList &old_thread_list,
514-
ThreadList &new_thread_list) {
513+
bool ProcessWindows::DoUpdateThreadList(ThreadList &old_thread_list,
514+
ThreadList &new_thread_list) {
515515
Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_THREAD);
516516
// Add all the threads that were previously running and for which we did not
517517
// detect a thread exited event.

lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ class ProcessWindows : public Process, public ProcessDebugger {
6969
bool CanDebug(lldb::TargetSP target_sp,
7070
bool plugin_specified_by_name) override;
7171
bool DestroyRequiresHalt() override { return false; }
72-
bool UpdateThreadList(ThreadList &old_thread_list,
73-
ThreadList &new_thread_list) override;
72+
bool DoUpdateThreadList(ThreadList &old_thread_list,
73+
ThreadList &new_thread_list) override;
7474
bool IsAlive() override;
7575

7676
size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,

lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,8 @@ lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
261261
return m_dyld_up.get();
262262
}
263263

264-
bool ProcessElfCore::UpdateThreadList(ThreadList &old_thread_list,
265-
ThreadList &new_thread_list) {
264+
bool ProcessElfCore::DoUpdateThreadList(ThreadList &old_thread_list,
265+
ThreadList &new_thread_list) {
266266
const uint32_t num_threads = GetNumThreadContexts();
267267
if (!m_thread_data_valid)
268268
return false;

lldb/source/Plugins/Process/elf-core/ProcessElfCore.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
105105
protected:
106106
void Clear();
107107

108-
bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
109-
lldb_private::ThreadList &new_thread_list) override;
108+
bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
109+
lldb_private::ThreadList &new_thread_list) override;
110110

111111
private:
112112
struct NT_FILE_Entry {

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,8 +1602,8 @@ bool ProcessGDBRemote::UpdateThreadIDList() {
16021602
return true;
16031603
}
16041604

1605-
bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list,
1606-
ThreadList &new_thread_list) {
1605+
bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list,
1606+
ThreadList &new_thread_list) {
16071607
// locker will keep a mutex locked until it goes out of scope
16081608
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_THREAD));
16091609
LLDB_LOGV(log, "pid = {0}", GetID());

lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ class ProcessGDBRemote : public Process,
312312

313313
void Clear();
314314

315-
bool UpdateThreadList(ThreadList &old_thread_list,
316-
ThreadList &new_thread_list) override;
315+
bool DoUpdateThreadList(ThreadList &old_thread_list,
316+
ThreadList &new_thread_list) override;
317317

318318
Status ConnectToReplayServer();
319319

lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,8 @@ lldb_private::DynamicLoader *ProcessMachCore::GetDynamicLoader() {
536536
return m_dyld_up.get();
537537
}
538538

539-
bool ProcessMachCore::UpdateThreadList(ThreadList &old_thread_list,
540-
ThreadList &new_thread_list) {
539+
bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list,
540+
ThreadList &new_thread_list) {
541541
if (old_thread_list.GetSize(false) == 0) {
542542
// Make up the thread the first time this is called so we can setup our one
543543
// and only core thread state.

lldb/source/Plugins/Process/mach-core/ProcessMachCore.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ class ProcessMachCore : public lldb_private::PostMortemProcess {
8181

8282
void Clear();
8383

84-
bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
85-
lldb_private::ThreadList &new_thread_list) override;
84+
bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list,
85+
lldb_private::ThreadList &new_thread_list) override;
8686

8787
lldb_private::ObjectFile *GetCoreObjectFile();
8888

lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,8 @@ Status ProcessMinidump::GetMemoryRegions(MemoryRegionInfos &region_list) {
462462

463463
void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
464464

465-
bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list,
466-
ThreadList &new_thread_list) {
465+
bool ProcessMinidump::DoUpdateThreadList(ThreadList &old_thread_list,
466+
ThreadList &new_thread_list) {
467467
for (const minidump::Thread &thread : m_thread_list) {
468468
LocationDescriptor context_location = thread.Context;
469469

lldb/source/Plugins/Process/minidump/ProcessMinidump.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ class ProcessMinidump : public PostMortemProcess {
9898
protected:
9999
void Clear();
100100

101-
bool UpdateThreadList(ThreadList &old_thread_list,
102-
ThreadList &new_thread_list) override;
101+
bool DoUpdateThreadList(ThreadList &old_thread_list,
102+
ThreadList &new_thread_list) override;
103103

104104
void ReadModuleList();
105105

lldb/source/Target/Process.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,12 @@ bool Process::SetProcessExitStatus(
10791079
return false;
10801080
}
10811081

1082+
bool Process::UpdateThreadList(ThreadList &old_thread_list,
1083+
ThreadList &new_thread_list) {
1084+
m_thread_plans.ClearThreadCache();
1085+
return DoUpdateThreadList(old_thread_list, new_thread_list);
1086+
}
1087+
10821088
void Process::UpdateThreadListIfNeeded() {
10831089
const uint32_t stop_id = GetStopID();
10841090
if (m_thread_list.GetSize(false) == 0 ||

lldb/source/Target/ProcessTrace.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ void ProcessTrace::DidAttach(ArchSpec &process_arch) {
7878
Process::DidAttach(process_arch);
7979
}
8080

81-
bool ProcessTrace::UpdateThreadList(ThreadList &old_thread_list,
82-
ThreadList &new_thread_list) {
81+
bool ProcessTrace::DoUpdateThreadList(ThreadList &old_thread_list,
82+
ThreadList &new_thread_list) {
8383
return false;
8484
}
8585

lldb/source/Target/ThreadPlan.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ Vote ThreadPlan::ShouldReportRun(Event *event_ptr) {
9999
return m_run_vote;
100100
}
101101

102+
void ThreadPlan::ClearThreadCache() { m_thread = nullptr; }
103+
102104
bool ThreadPlan::StopOthers() {
103105
ThreadPlan *prev_plan;
104106
prev_plan = GetPreviousPlan();
@@ -134,7 +136,7 @@ bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) {
134136
}
135137
}
136138
bool success = DoWillResume(resume_state, current_plan);
137-
m_thread = nullptr; // We don't cache the thread pointer over resumes. This
139+
ClearThreadCache(); // We don't cache the thread pointer over resumes. This
138140
// Thread might go away, and another Thread represent
139141
// the same underlying object on a later stop.
140142
return success;

lldb/source/Target/ThreadPlanStack.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,11 @@ ThreadPlan *ThreadPlanStack::GetInnermostExpression() const {
369369
return nullptr;
370370
}
371371

372+
void ThreadPlanStack::ClearThreadCache() {
373+
for (lldb::ThreadPlanSP thread_plan_sp : m_plans)
374+
thread_plan_sp->ClearThreadCache();
375+
}
376+
372377
void ThreadPlanStack::WillResume() {
373378
m_completed_plans.clear();
374379
m_discarded_plans.clear();

lldb/test/API/functionalities/exec/TestExec.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,68 @@ def cleanup():
115115
self.runCmd("bt")
116116
self.assertTrue(len(threads) == 1,
117117
"Stopped at breakpoint in exec'ed process.")
118+
119+
@expectedFailureAll(archs=['i386'],
120+
oslist=no_match(["freebsd"]),
121+
bugnumber="rdar://28656532")
122+
@expectedFailureAll(oslist=["ios", "tvos", "watchos", "bridgeos"], bugnumber="rdar://problem/34559552") # this exec test has problems on ios systems
123+
@expectedFailureNetBSD
124+
@skipIfAsan # rdar://problem/43756823
125+
@skipIfWindows
126+
def test_correct_thread_plan_state_before_exec(self):
127+
'''
128+
In this test we make sure that the Thread* cache in the ThreadPlans
129+
is cleared correctly when performing exec
130+
'''
131+
132+
self.build()
133+
exe = self.getBuildArtifact("a.out")
134+
target = self.dbg.CreateTarget(exe)
135+
136+
(target, process, thread, breakpoint1) = lldbutil.run_to_source_breakpoint(
137+
self, 'Set breakpoint 1 here', lldb.SBFileSpec('main.cpp', False))
138+
139+
# The stop reason of the thread should be breakpoint.
140+
self.assertTrue(process.GetState() == lldb.eStateStopped,
141+
STOPPED_DUE_TO_BREAKPOINT)
142+
143+
threads = lldbutil.get_threads_stopped_at_breakpoint(process, breakpoint1)
144+
self.assertTrue(len(threads) == 1)
145+
146+
# We perform an instruction step, which effectively sets the cache of the base
147+
# thread plan, which should be cleared when a new thread list appears.
148+
#
149+
# Continuing after this instruction step will trigger a call to
150+
# ThreadPlan::ShouldReportRun, which sets the ThreadPlan's Thread cache to
151+
# the old Thread* value. In Process::UpdateThreadList we are clearing this
152+
# cache in preparation for the new ThreadList.
153+
#
154+
# Not doing this stepping will cause LLDB to first execute a private single step
155+
# past the current breakpoint, which eventually avoids the call to ShouldReportRun,
156+
# thus not setting the cache to its invalid value.
157+
thread.StepInstruction(False)
158+
159+
# Run and we should stop due to exec
160+
breakpoint2 = target.BreakpointCreateBySourceRegex(
161+
'Set breakpoint 2 here', lldb.SBFileSpec("secondprog.cpp", False))
162+
163+
process.Continue()
164+
165+
self.assertFalse(process.GetState() == lldb.eStateExited,
166+
"Process should not have exited!")
167+
self.assertTrue(process.GetState() == lldb.eStateStopped,
168+
"Process should be stopped at __dyld_start")
169+
170+
threads = lldbutil.get_stopped_threads(
171+
process, lldb.eStopReasonExec)
172+
self.assertTrue(
173+
len(threads) == 1,
174+
"We got a thread stopped for exec.")
175+
176+
# Run and we should stop at breakpoint in main after exec
177+
process.Continue()
178+
179+
threads = lldbutil.get_threads_stopped_at_breakpoint(
180+
process, breakpoint2)
181+
self.assertTrue(len(threads) == 1,
182+
"Stopped at breakpoint in exec'ed process.")

lldb/unittests/Process/ProcessEventDataTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ class DummyProcess : public Process {
5353
Status &error) {
5454
return 0;
5555
}
56-
virtual bool UpdateThreadList(ThreadList &old_thread_list,
57-
ThreadList &new_thread_list) {
56+
bool DoUpdateThreadList(ThreadList &old_thread_list,
57+
ThreadList &new_thread_list) override {
5858
return false;
5959
}
6060
virtual ConstString GetPluginName() { return ConstString("Dummy"); }

lldb/unittests/Target/ExecutionContextTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ class DummyProcess : public Process {
5858
Status &error) {
5959
return 0;
6060
}
61-
virtual bool UpdateThreadList(ThreadList &old_thread_list,
62-
ThreadList &new_thread_list) {
61+
bool DoUpdateThreadList(ThreadList &old_thread_list,
62+
ThreadList &new_thread_list) override {
6363
return false;
6464
}
6565
virtual ConstString GetPluginName() { return ConstString("Dummy"); }

lldb/unittests/Thread/ThreadTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ class DummyProcess : public Process {
5151
Status &error) {
5252
return 0;
5353
}
54-
virtual bool UpdateThreadList(ThreadList &old_thread_list,
55-
ThreadList &new_thread_list) {
54+
bool DoUpdateThreadList(ThreadList &old_thread_list,
55+
ThreadList &new_thread_list) override {
5656
return false;
5757
}
5858
virtual ConstString GetPluginName() { return ConstString("Dummy"); }

0 commit comments

Comments
 (0)