Skip to content

Commit ec4ecbd

Browse files
authored
Merge pull request #6477 from jimingham/fix-run-locker-again
Fix the run locker setting for async launches that don't stop at the
2 parents 4e70baf + 23c9ec9 commit ec4ecbd

File tree

6 files changed

+152
-8
lines changed

6 files changed

+152
-8
lines changed

lldb/source/API/SBFrame.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "lldb/Core/StructuredDataImpl.h"
2121
#include "lldb/Core/ValueObjectRegister.h"
2222
#include "lldb/Core/ValueObjectVariable.h"
23+
#include "lldb/Core/ValueObjectConstResult.h"
2324
#include "lldb/Expression/ExpressionVariable.h"
2425
#include "lldb/Expression/UserExpression.h"
2526
#include "lldb/Host/Host.h"
@@ -997,6 +998,12 @@ SBValue SBFrame::EvaluateExpression(const char *expr) {
997998
else
998999
options.SetLanguage(frame->GetLanguage());
9991000
return EvaluateExpression(expr, options);
1001+
} else {
1002+
Status error;
1003+
error.SetErrorString("can't evaluate expressions when the "
1004+
"process is running.");
1005+
ValueObjectSP error_val_sp = ValueObjectConstResult::Create(nullptr, error);
1006+
result.SetSP(error_val_sp, false);
10001007
}
10011008
return result;
10021009
}
@@ -1060,7 +1067,6 @@ lldb::SBValue SBFrame::EvaluateExpression(const char *expr,
10601067
std::unique_lock<std::recursive_mutex> lock;
10611068
ExecutionContext exe_ctx(m_opaque_sp.get(), lock);
10621069

1063-
10641070
StackFrame *frame = nullptr;
10651071
Target *target = exe_ctx.GetTargetPtr();
10661072
Process *process = exe_ctx.GetProcessPtr();
@@ -1084,13 +1090,30 @@ lldb::SBValue SBFrame::EvaluateExpression(const char *expr,
10841090
target->EvaluateExpression(expr, frame, expr_value_sp, options.ref());
10851091
expr_result.SetSP(expr_value_sp, options.GetFetchDynamicValue());
10861092
}
1093+
} else {
1094+
Status error;
1095+
error.SetErrorString("can't evaluate expressions when the "
1096+
"process is running.");
1097+
expr_value_sp = ValueObjectConstResult::Create(nullptr, error);
1098+
expr_result.SetSP(expr_value_sp, false);
10871099
}
1100+
} else {
1101+
Status error;
1102+
error.SetErrorString("sbframe object is not valid.");
1103+
expr_value_sp = ValueObjectConstResult::Create(nullptr, error);
1104+
expr_result.SetSP(expr_value_sp, false);
10881105
}
10891106

1090-
LLDB_LOGF(expr_log,
1091-
"** [SBFrame::EvaluateExpression] Expression result is "
1092-
"%s, summary %s **",
1093-
expr_result.GetValue(), expr_result.GetSummary());
1107+
if (expr_result.GetError().Success())
1108+
LLDB_LOGF(expr_log,
1109+
"** [SBFrame::EvaluateExpression] Expression result is "
1110+
"%s, summary %s **",
1111+
expr_result.GetValue(), expr_result.GetSummary());
1112+
else
1113+
LLDB_LOGF(expr_log,
1114+
"** [SBFrame::EvaluateExpression] Expression evaluation failed: "
1115+
"%s **",
1116+
expr_result.GetError().GetCString());
10941117

10951118
return expr_result;
10961119
}

lldb/source/API/SBTarget.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,12 +2278,25 @@ lldb::SBValue SBTarget::EvaluateExpression(const char *expr,
22782278
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
22792279
ExecutionContext exe_ctx(m_opaque_sp.get());
22802280

2281-
22822281
frame = exe_ctx.GetFramePtr();
22832282
Target *target = exe_ctx.GetTargetPtr();
2283+
Process *process = exe_ctx.GetProcessPtr();
22842284

22852285
if (target) {
2286-
target->EvaluateExpression(expr, frame, expr_value_sp, options.ref());
2286+
// If we have a process, make sure to lock the runlock:
2287+
if (process) {
2288+
Process::StopLocker stop_locker;
2289+
if (stop_locker.TryLock(&process->GetRunLock())) {
2290+
target->EvaluateExpression(expr, frame, expr_value_sp, options.ref());
2291+
} else {
2292+
Status error;
2293+
error.SetErrorString("can't evaluate expressions when the "
2294+
"process is running.");
2295+
expr_value_sp = ValueObjectConstResult::Create(nullptr, error);
2296+
}
2297+
} else {
2298+
target->EvaluateExpression(expr, frame, expr_value_sp, options.ref());
2299+
}
22872300

22882301
expr_result.SetSP(expr_value_sp, options.GetFetchDynamicValue());
22892302
}

lldb/source/Target/Target.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3627,7 +3627,7 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) {
36273627
// SyncResume hijacker.
36283628
m_process_sp->ResumeSynchronous(stream);
36293629
else
3630-
error = m_process_sp->PrivateResume();
3630+
error = m_process_sp->Resume();
36313631
if (!error.Success()) {
36323632
Status error2;
36333633
error2.SetErrorStringWithFormat(
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
C_SOURCES := main.c
2+
CFLAGS_EXTRAS := -std=c99
3+
4+
include Makefile.rules
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
"""
2+
Test that the run locker really does work to keep
3+
us from running SB API that should only be run
4+
while stopped. This test is mostly concerned with
5+
what happens between launch and first stop.
6+
"""
7+
8+
import lldb
9+
import lldbsuite.test.lldbutil as lldbutil
10+
from lldbsuite.test.lldbtest import *
11+
12+
13+
class TestRunLocker(TestBase):
14+
15+
NO_DEBUG_INFO_TESTCASE = True
16+
17+
def test_run_locker(self):
18+
"""Test that the run locker is set correctly when we launch"""
19+
self.build()
20+
self.runlocker_test(False)
21+
22+
def test_run_locker_stop_at_entry(self):
23+
"""Test that the run locker is set correctly when we launch"""
24+
self.build()
25+
self.runlocker_test(False)
26+
27+
def setUp(self):
28+
# Call super's setUp().
29+
TestBase.setUp(self)
30+
self.main_source_file = lldb.SBFileSpec("main.c")
31+
32+
def runlocker_test(self, stop_at_entry):
33+
"""The code to stop at entry handles events slightly differently, so
34+
we test both versions of process launch."""
35+
36+
target = lldbutil.run_to_breakpoint_make_target(self)
37+
38+
launch_info = target.GetLaunchInfo()
39+
if stop_at_entry:
40+
flags = launch_info.GetFlags()
41+
launch_info.SetFlags(flags | lldb.eLaunchFlagStopAtEntry)
42+
43+
error = lldb.SBError()
44+
# We are trying to do things when the process is running, so
45+
# we have to run the debugger asynchronously.
46+
self.dbg.SetAsync(True)
47+
48+
listener = lldb.SBListener("test-run-lock-listener")
49+
launch_info.SetListener(listener)
50+
process = target.Launch(launch_info, error)
51+
self.assertSuccess(error, "Launched the process")
52+
53+
event = lldb.SBEvent()
54+
55+
event_result = listener.WaitForEvent(10, event)
56+
self.assertTrue(event_result, "timed out waiting for launch")
57+
state_type = lldb.SBProcess.GetStateFromEvent(event)
58+
# We don't always see a launching...
59+
if state_type == lldb.eStateLaunching:
60+
event_result = listener.WaitForEvent(10, event)
61+
self.assertTrue(event_result, "Timed out waiting for running after launching")
62+
state_type = lldb.SBProcess.GetStateFromEvent(event)
63+
64+
self.assertState(state_type, lldb.eStateRunning, "Didn't get a running event")
65+
66+
# We aren't checking the entry state, but just making sure
67+
# the running state is set properly if we continue in this state.
68+
69+
if stop_at_entry:
70+
event_result = listener.WaitForEvent(10, event)
71+
self.assertTrue(event_result, "Timed out waiting for stop at entry stop")
72+
state_type = lldb.SBProcess.GetStateFromEvent(event)
73+
self.assertState(state_type, eStateStopped, "Stop at entry stopped")
74+
process.Continue()
75+
76+
# Okay, now the process is running, make sure we can't do things
77+
# you aren't supposed to do while running, and that we get some
78+
# actual error:
79+
val = target.EvaluateExpression("SomethingToCall()")
80+
error = val.GetError()
81+
self.assertTrue(error.Fail(), "Failed to run expression")
82+
print(f"Got Error: {error.GetCString()}")
83+
self.assertIn("can't evaluate expressions when the process is running", error.GetCString(), "Stopped by stop locker")
84+
85+
# This should also fail if we try to use the script interpreter directly:
86+
interp = self.dbg.GetCommandInterpreter()
87+
result = lldb.SBCommandReturnObject()
88+
ret = interp.HandleCommand("script var = lldb.frame.EvaluateExpression('SomethingToCall()'); var.GetError().GetCString()", result)
89+
self.assertIn("can't evaluate expressions when the process is running", result.GetOutput())
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <unistd.h>
2+
3+
int
4+
SomethingToCall() {
5+
return 100;
6+
}
7+
8+
int
9+
main()
10+
{
11+
while (1) {
12+
sleep(1);
13+
}
14+
return SomethingToCall();
15+
}

0 commit comments

Comments
 (0)