Skip to content

Commit 4c80e26

Browse files
author
walter erquinigo
committed
[LLDB] Add a target.launch-working-dir setting
Internally we use bazel in a way in which it can drop you in a LLDB session with the target launched in a particular cwd, which is needed for things to work. We've been making this automation work via `process launch -w`. However, if later the user wants to restart the process with `r`, then they end up using a different cwd for relaunching the process. As a way to fix this, I'm adding a target-level setting that allows setting a default cwd used for launching the process without needing the user to specify it manually.
1 parent a91ebcd commit 4c80e26

File tree

5 files changed

+91
-0
lines changed

5 files changed

+91
-0
lines changed

lldb/include/lldb/Target/Target.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "lldb/Utility/RealpathPrefixes.h"
3838
#include "lldb/Utility/Timeout.h"
3939
#include "lldb/lldb-public.h"
40+
#include "llvm/ADT/StringRef.h"
4041

4142
namespace lldb_private {
4243

@@ -114,6 +115,8 @@ class TargetProperties : public Properties {
114115

115116
void SetDisableSTDIO(bool b);
116117

118+
std::optional<llvm::StringRef> GetLaunchWorkingDirectory() const;
119+
117120
const char *GetDisassemblyFlavor() const;
118121

119122
InlineStrategy GetInlineStrategy() const;

lldb/source/Commands/CommandObjectProcess.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,13 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
201201
if (target->GetDisableSTDIO())
202202
m_options.launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO);
203203

204+
if (!m_options.launch_info.GetWorkingDirectory()) {
205+
if (std::optional<llvm::StringRef> wd =
206+
target->GetLaunchWorkingDirectory()) {
207+
m_options.launch_info.SetWorkingDirectory(FileSpec(*wd));
208+
}
209+
}
210+
204211
// Merge the launch info environment with the target environment.
205212
Environment target_env = target->GetEnvironment();
206213
m_options.launch_info.GetEnvironment().insert(target_env.begin(),

lldb/source/Target/Target.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4428,6 +4428,15 @@ void TargetProperties::SetDisableSTDIO(bool b) {
44284428
const uint32_t idx = ePropertyDisableSTDIO;
44294429
SetPropertyAtIndex(idx, b);
44304430
}
4431+
std::optional<llvm::StringRef>
4432+
TargetProperties::GetLaunchWorkingDirectory() const {
4433+
const uint32_t idx = ePropertyLaunchWorkingDir;
4434+
llvm::StringRef value = GetPropertyAtIndexAs<llvm::StringRef>(
4435+
idx, g_target_properties[idx].default_cstr_value);
4436+
if (value.empty())
4437+
return {};
4438+
return value;
4439+
}
44314440

44324441
const char *TargetProperties::GetDisassemblyFlavor() const {
44334442
const uint32_t idx = ePropertyDisassemblyFlavor;

lldb/source/Target/TargetProperties.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,10 @@ let Definition = "target" in {
201201
def DebugUtilityExpression: Property<"debug-utility-expression", "Boolean">,
202202
DefaultFalse,
203203
Desc<"Enable debugging of LLDB-internal utility expressions.">;
204+
def LaunchWorkingDir: Property<"launch-working-dir", "String">,
205+
DefaultStringValue<"">,
206+
Desc<"A default value for the working directory to use when launching processes. "
207+
"It's not used when empty.">;
204208
}
205209

206210
let Definition = "process_experimental" in {

lldb/test/API/commands/process/launch/TestProcessLaunch.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from lldbsuite.test.decorators import *
99
from lldbsuite.test.lldbtest import *
1010
from lldbsuite.test import lldbutil
11+
from pathlib import Path
1112

1213

1314
class ProcessLaunchTestCase(TestBase):
@@ -206,3 +207,70 @@ def test_environment_with_special_char(self):
206207
self.assertEqual(value, evil_var)
207208
process.Continue()
208209
self.assertState(process.GetState(), lldb.eStateExited, PROCESS_EXITED)
210+
211+
def test_target_launch_working_dir_prop(self):
212+
"""Test that the setting `target.launch-working-dir` is correctly used when launching a process."""
213+
d = {"CXX_SOURCES": "print_cwd.cpp"}
214+
self.build(dictionary=d)
215+
self.setTearDownCleanup(d)
216+
exe = self.getBuildArtifact("a.out")
217+
self.runCmd("file " + exe)
218+
219+
mywd = "my_working_dir"
220+
out_file_name = "my_working_dir_test.out"
221+
222+
my_working_dir_path = self.getBuildArtifact(mywd)
223+
lldbutil.mkdir_p(my_working_dir_path)
224+
out_file_path = os.path.join(my_working_dir_path, out_file_name)
225+
another_working_dir_path = Path(
226+
os.path.join(my_working_dir_path, "..")
227+
).resolve()
228+
229+
# Check that we correctly override the working dir
230+
launch_command = f"process launch -w {my_working_dir_path} -o {out_file_path}"
231+
232+
self.expect(
233+
launch_command,
234+
patterns=["Process .* launched: .*a.out"],
235+
)
236+
237+
out = lldbutil.read_file_on_target(self, out_file_path)
238+
self.assertIn(f"stdout: {my_working_dir_path}", out)
239+
240+
# Check that we can unset the setting
241+
self.runCmd(f"settings set target.launch-working-dir ''")
242+
launch_command = f"process launch -o {out_file_path}"
243+
244+
self.expect(
245+
launch_command,
246+
patterns=["Process .* launched: .*a.out"],
247+
)
248+
249+
out = lldbutil.read_file_on_target(self, out_file_path)
250+
self.assertNotIn(f"stdout: {another_working_dir_path}", out)
251+
252+
# Check that we correctly set the working dir
253+
self.runCmd(
254+
f"settings set target.launch-working-dir {another_working_dir_path}"
255+
)
256+
launch_command = f"process launch -o {out_file_path}"
257+
258+
self.expect(
259+
launch_command,
260+
patterns=["Process .* launched: .*a.out"],
261+
)
262+
263+
out = lldbutil.read_file_on_target(self, out_file_path)
264+
self.assertIn(f"stdout: {another_working_dir_path}", out)
265+
266+
# Check that we can unset the setting
267+
self.runCmd(f"settings set target.launch-working-dir ''")
268+
launch_command = f"process launch -o {out_file_path}"
269+
270+
self.expect(
271+
launch_command,
272+
patterns=["Process .* launched: .*a.out"],
273+
)
274+
275+
out = lldbutil.read_file_on_target(self, out_file_path)
276+
self.assertNotIn(f"stdout: {another_working_dir_path}", out)

0 commit comments

Comments
 (0)