wallace updated this revision to Diff 251200. wallace added a comment. Addressed Greg's comments.
At the end I ended up not using APIs that use the format NAME=value, as they could be error prone. I think it's safer to use functions that work with explicit names and values. Besides, I don't want to complicate this diff, so for now I'd prefer not to add setters for Platform and Target using the Environment class. We can add that later when we need it. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D76111/new/ https://reviews.llvm.org/D76111 Files: lldb/bindings/headers.swig lldb/bindings/interface/SBEnvironment.i lldb/bindings/interface/SBPlatform.i lldb/bindings/interface/SBTarget.i lldb/bindings/interfaces.swig lldb/include/lldb/API/LLDB.h lldb/include/lldb/API/SBDefines.h lldb/include/lldb/API/SBEnvironment.h lldb/include/lldb/API/SBPlatform.h lldb/include/lldb/API/SBTarget.h lldb/include/lldb/Utility/Environment.h lldb/include/lldb/lldb-forward.h lldb/source/API/CMakeLists.txt lldb/source/API/SBEnvironment.cpp lldb/source/API/SBPlatform.cpp lldb/source/API/SBTarget.cpp lldb/test/API/python_api/sbenvironment/TestSBEnvironment.py
Index: lldb/test/API/python_api/sbenvironment/TestSBEnvironment.py =================================================================== --- /dev/null +++ lldb/test/API/python_api/sbenvironment/TestSBEnvironment.py @@ -0,0 +1,86 @@ +"""Test the SBEnvironment APIs.""" + + + +from math import fabs +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +def forEachEntry(env, callback): + for i in range(0, env.GetNumValues()): + name = env.GetNameAtIndex(i) + value = env.GetValueAtIndex(i) + callback(name, value) + + +class SBEnvironmentAPICase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + + @add_test_categories(['pyapi']) + def test_platform_environment(self): + env = self.dbg.GetSelectedPlatform().GetEnvironment() + # We assume at least PATH is set + self.assertNotEqual(env.Get("PATH"), None) + + + @add_test_categories(['pyapi']) + def test_target_environment(self): + env = self.dbg.GetSelectedTarget().GetEnvironment() + # There is no target, so env should be empty + self.assertEqual(env.GetNumValues(), 0) + self.assertEqual(env.Get("PATH"), None) + + target = self.dbg.CreateTarget("") + env = target.GetEnvironment() + path = env.Get("PATH") + # Now there's a target, so at least PATH should exist + self.assertNotEqual(path, None) + + # Make sure we are getting a copy by modifying the env we just got + env.Set("PATH", "#" + path, overwrite=True) + self.assertEqual(target.GetEnvironment().Get("PATH"), path) + + @add_test_categories(['pyapi']) + def test_creating_and_modifying_environment(self): + env = lldb.SBEnvironment() + + self.assertEqual(env.Get("FOO"), None) + self.assertEqual(env.Get("BAR"), None) + + # We also test empty values + self.assertTrue(env.Set("FOO", "", overwrite=False)) + env.Set("BAR", "foo", overwrite=False) + + self.assertEqual(env.Get("FOO"), "") + self.assertEqual(env.Get("BAR"), "foo") + + self.assertEqual(env.GetNumValues(), 2) + + forEachEntry( + env, + lambda name, value: + self.assertIn(name + '=' + value, ["FOO=", "BAR=foo"]) + ) + + # Make sure modifications work + self.assertFalse(env.Set("FOO", "bar", overwrite=False)) + self.assertEqual(env.Get("FOO"), "") + + self.assertTrue(env.Set("FOO", "bar", overwrite=True)) + self.assertEqual(env.Get("FOO"), "bar") + + forEachEntry( + env, + lambda name, value: + self.assertIn(name + '=' + value, ["FOO=bar", "BAR=foo"]) + ) + + # Make sure we can unset + self.assertTrue(env.Unset("FOO")) + self.assertFalse(env.Unset("FOO")) + self.assertEqual(env.Get("FOO"), None) \ No newline at end of file Index: lldb/source/API/SBTarget.cpp =================================================================== --- lldb/source/API/SBTarget.cpp +++ lldb/source/API/SBTarget.cpp @@ -13,6 +13,7 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBDebugger.h" +#include "lldb/API/SBEnvironment.h" #include "lldb/API/SBEvent.h" #include "lldb/API/SBExpressionOptions.h" #include "lldb/API/SBFileSpec.h" @@ -2388,6 +2389,17 @@ m_opaque_sp->SetProcessLaunchInfo(launch_info.ref()); } +SBEnvironment SBTarget::GetEnvironment() { + LLDB_RECORD_METHOD_NO_ARGS(lldb::SBEnvironment, SBTarget, GetEnvironment); + TargetSP target_sp(GetSP()); + + if (target_sp) { + return LLDB_RECORD_RESULT(SBEnvironment(target_sp->GetEnvironment())); + } + + return LLDB_RECORD_RESULT(SBEnvironment()); +} + namespace lldb_private { namespace repro { @@ -2643,6 +2655,7 @@ LLDB_REGISTER_METHOD(lldb::SBInstructionList, SBTarget, GetInstructionsWithFlavor, (lldb::addr_t, const char *, const void *, size_t)); + LLDB_REGISTER_METHOD(lldb::SBEnvironment, SBTarget, GetEnvironment, ()); } } Index: lldb/source/API/SBPlatform.cpp =================================================================== --- lldb/source/API/SBPlatform.cpp +++ lldb/source/API/SBPlatform.cpp @@ -8,9 +8,11 @@ #include "lldb/API/SBPlatform.h" #include "SBReproducerPrivate.h" +#include "lldb/API/SBEnvironment.h" #include "lldb/API/SBError.h" #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBLaunchInfo.h" +#include "lldb/API/SBPlatform.h" #include "lldb/API/SBUnixSignals.h" #include "lldb/Host/File.h" #include "lldb/Target/Platform.h" @@ -649,6 +651,17 @@ return LLDB_RECORD_RESULT(SBUnixSignals()); } +SBEnvironment SBPlatform::GetEnvironment() { + LLDB_RECORD_METHOD_NO_ARGS(lldb::SBEnvironment, SBPlatform, GetEnvironment); + PlatformSP platform_sp(GetSP()); + + if (platform_sp) { + return LLDB_RECORD_RESULT(SBEnvironment(platform_sp->GetEnvironment())); + } + + return LLDB_RECORD_RESULT(SBEnvironment()); +} + namespace lldb_private { namespace repro { @@ -740,6 +753,7 @@ (const char *)); LLDB_REGISTER_METHOD(lldb::SBError, SBPlatform, SetFilePermissions, (const char *, uint32_t)); + LLDB_REGISTER_METHOD(lldb::SBEnvironment, SBPlatform, GetEnvironment, ()); LLDB_REGISTER_METHOD_CONST(lldb::SBUnixSignals, SBPlatform, GetUnixSignals, ()); } Index: lldb/source/API/SBEnvironment.cpp =================================================================== --- /dev/null +++ lldb/source/API/SBEnvironment.cpp @@ -0,0 +1,111 @@ +//===-- SBEnvironment.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBEnvironment.h" +#include "SBReproducerPrivate.h" +#include "Utils.h" +#include "lldb/API/SBStringList.h" +#include "lldb/Utility/Environment.h" + +using namespace lldb; +using namespace lldb_private; + +SBEnvironment::SBEnvironment() : m_opaque_up(new Environment()) { + LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBEnvironment); +} + +SBEnvironment::SBEnvironment(const SBEnvironment &rhs) + : m_opaque_up(new Environment()) { + LLDB_RECORD_CONSTRUCTOR(SBEnvironment, (const lldb::SBEnvironment &), rhs); + + m_opaque_up = clone(rhs.m_opaque_up); +} + +SBEnvironment::SBEnvironment(const Environment &rhs) + : m_opaque_up(new Environment(rhs)) {} + +SBEnvironment::~SBEnvironment() = default; + +const SBEnvironment &SBEnvironment::operator=(const SBEnvironment &rhs) { + LLDB_RECORD_METHOD(const lldb::SBEnvironment &, + SBEnvironment, operator=,(const lldb::SBEnvironment &), + rhs); + + if (this != &rhs) + m_opaque_up = clone(rhs.m_opaque_up); + return LLDB_RECORD_RESULT(*this); +} + +size_t SBEnvironment::GetNumValues() { + LLDB_RECORD_METHOD_NO_ARGS(size_t, SBEnvironment, GetNumValues); + return LLDB_RECORD_RESULT(m_opaque_up->size()); +} + +const char *SBEnvironment::Get(const char *name) { + LLDB_RECORD_METHOD(const char *, SBEnvironment, Get, (const char *), name); + if (m_opaque_up->find(name) == m_opaque_up->end()) + return LLDB_RECORD_RESULT(nullptr); + return LLDB_RECORD_RESULT( + ConstString(m_opaque_up->lookup(name)).AsCString("")); +} + +const char *SBEnvironment::GetNameAtIndex(size_t index) { + LLDB_RECORD_METHOD(const char *, SBEnvironment, GetNameAtIndex, (size_t), + index); + if (index < 0 || index >= GetNumValues()) + return LLDB_RECORD_RESULT(nullptr); + return LLDB_RECORD_RESULT( + ConstString(std::next(m_opaque_up->begin(), index)->first()) + .AsCString("")); +} + +const char *SBEnvironment::GetValueAtIndex(size_t index) { + LLDB_RECORD_METHOD(const char *, SBEnvironment, GetValueAtIndex, (size_t), + index); + if (index < 0 || index >= GetNumValues()) + return LLDB_RECORD_RESULT(nullptr); + return LLDB_RECORD_RESULT( + ConstString(std::next(m_opaque_up->begin(), index)->second) + .AsCString("")); +} + +bool SBEnvironment::Set(const char *name, const char *value, bool overwrite) { + LLDB_RECORD_METHOD(bool, SBEnvironment, Set, + (const char *, const char *, bool), name, value, + overwrite); + if (overwrite || m_opaque_up->find(name) == m_opaque_up->end()) { + m_opaque_up->insert_or_assign(name, std::string(value)); + return LLDB_RECORD_RESULT(true); + } + return LLDB_RECORD_RESULT(false); +} + +bool SBEnvironment::Unset(const char *name) { + LLDB_RECORD_METHOD(bool, SBEnvironment, Unset, (const char *), name); + return LLDB_RECORD_RESULT(m_opaque_up->erase(name)); +} + +namespace lldb_private { +namespace repro { + +template <> void RegisterMethods<SBEnvironment>(Registry &R) { + LLDB_REGISTER_CONSTRUCTOR(SBEnvironment, ()); + LLDB_REGISTER_CONSTRUCTOR(SBEnvironment, (const lldb::SBEnvironment &)); + LLDB_REGISTER_METHOD(const lldb::SBEnvironment &, + SBEnvironment, operator=,(const lldb::SBEnvironment &)); + LLDB_REGISTER_METHOD(size_t, SBEnvironment, GetNumValues, ()); + LLDB_REGISTER_METHOD(const char *, SBEnvironment, GetNameAtIndex, (size_t)); + LLDB_REGISTER_METHOD(const char *, SBEnvironment, GetValueAtIndex, (size_t)); + LLDB_REGISTER_METHOD(const char *, SBEnvironment, Get, (const char *)); + LLDB_REGISTER_METHOD(bool, SBEnvironment, Set, + (const char *, const char *, bool)); + LLDB_REGISTER_METHOD(bool, SBEnvironment, Unset, (const char *)); +} + +} // namespace repro +} // namespace lldb_private Index: lldb/source/API/CMakeLists.txt =================================================================== --- lldb/source/API/CMakeLists.txt +++ lldb/source/API/CMakeLists.txt @@ -35,6 +35,7 @@ SBData.cpp SBDebugger.cpp SBDeclaration.cpp + SBEnvironment.cpp SBError.cpp SBEvent.cpp SBExecutionContext.cpp Index: lldb/include/lldb/lldb-forward.h =================================================================== --- lldb/include/lldb/lldb-forward.h +++ lldb/include/lldb/lldb-forward.h @@ -76,6 +76,7 @@ class DynamicLoader; class Editline; class EmulateInstruction; +class Environment; class EvaluateExpressionOptions; class Event; class EventData; Index: lldb/include/lldb/Utility/Environment.h =================================================================== --- lldb/include/lldb/Utility/Environment.h +++ lldb/include/lldb/Utility/Environment.h @@ -50,6 +50,7 @@ using Base::erase; using Base::find; using Base::insert; + using Base::insert_or_assign; using Base::lookup; using Base::size; using Base::try_emplace; Index: lldb/include/lldb/API/SBTarget.h =================================================================== --- lldb/include/lldb/API/SBTarget.h +++ lldb/include/lldb/API/SBTarget.h @@ -94,6 +94,15 @@ /// A platform object. lldb::SBPlatform GetPlatform(); + /// Return the environment variables that would be used to launch a new + /// process. + /// + /// \return + /// An lldb::SBEnvironment object which is a copy of the target's + /// environment. + + SBEnvironment GetEnvironment(); + /// Install any binaries that need to be installed. /// /// This function does nothing when debugging on the host system. Index: lldb/include/lldb/API/SBPlatform.h =================================================================== --- lldb/include/lldb/API/SBPlatform.h +++ lldb/include/lldb/API/SBPlatform.h @@ -154,6 +154,14 @@ SBUnixSignals GetUnixSignals() const; + /// Return the environment variables of the remote platform connection + /// process. + /// + /// \return + /// An lldb::SBEnvironment object which is a copy of the platform's + /// enviroment. + SBEnvironment GetEnvironment(); + protected: friend class SBDebugger; friend class SBTarget; Index: lldb/include/lldb/API/SBEnvironment.h =================================================================== --- /dev/null +++ lldb/include/lldb/API/SBEnvironment.h @@ -0,0 +1,67 @@ +//===-- SBEnvironment.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_API_SBENVIRONMENT_H +#define LLDB_API_SBENVIRONMENT_H + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBEnvironment { +public: + SBEnvironment(); + + SBEnvironment(const lldb::SBEnvironment &rhs); + + ~SBEnvironment(); + + const lldb::SBEnvironment &operator=(const lldb::SBEnvironment &rhs); + + /// Return the value of a given environment variable. + /// + /// \return + /// The value of the enviroment variable or null if not present. + const char *Get(const char *name); + + /// \return + /// The name at the given index or null if the index is invalid. + const char *GetNameAtIndex(size_t index); + + /// \return + /// The value at the given index or null if the index is invalid. + const char *GetValueAtIndex(size_t index); + + size_t GetNumValues(); + + /// Set the value of a given environment variable. + /// If the variable exists, its value is updated only if overwrite is true. + /// + /// \return + /// Return whether the variable was added or modified. + bool Set(const char *name, const char *value, bool overwrite); + + /// Unset an environment variable if exists. + /// + /// \return + /// Return whether a variable was actually unset. + bool Unset(const char *name); + +protected: + friend class SBPlatform; + friend class SBTarget; + + SBEnvironment(const lldb_private::Environment &rhs); + +private: + std::unique_ptr<lldb_private::Environment> m_opaque_up; +}; + +} // namespace lldb + +#endif // LLDB_API_SBENVIRONMENT_H Index: lldb/include/lldb/API/SBDefines.h =================================================================== --- lldb/include/lldb/API/SBDefines.h +++ lldb/include/lldb/API/SBDefines.h @@ -35,6 +35,7 @@ class LLDB_API SBData; class LLDB_API SBDebugger; class LLDB_API SBDeclaration; +class LLDB_API SBEnvironment; class LLDB_API SBError; class LLDB_API SBEvent; class LLDB_API SBEventList; Index: lldb/include/lldb/API/LLDB.h =================================================================== --- lldb/include/lldb/API/LLDB.h +++ lldb/include/lldb/API/LLDB.h @@ -24,6 +24,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBDeclaration.h" #include "lldb/API/SBDefines.h" +#include "lldb/API/SBEnvironment.h" #include "lldb/API/SBError.h" #include "lldb/API/SBEvent.h" #include "lldb/API/SBExecutionContext.h" Index: lldb/bindings/interfaces.swig =================================================================== --- lldb/bindings/interfaces.swig +++ lldb/bindings/interfaces.swig @@ -29,6 +29,7 @@ %include "./interface/SBDebugger.i" %include "./interface/SBDeclaration.i" %include "./interface/SBError.i" +%include "./interface/SBEnvironment.i" %include "./interface/SBEvent.i" %include "./interface/SBExecutionContext.i" %include "./interface/SBExpressionOptions.i" Index: lldb/bindings/interface/SBTarget.i =================================================================== --- lldb/bindings/interface/SBTarget.i +++ lldb/bindings/interface/SBTarget.i @@ -677,6 +677,9 @@ lldb::SBBreakpoint BreakpointCreateByAddress (addr_t address); + lldb::SBEnvironment + GetEnvironment(); + lldb::SBBreakpoint BreakpointCreateBySBAddress (SBAddress &sb_address); Index: lldb/bindings/interface/SBPlatform.i =================================================================== --- lldb/bindings/interface/SBPlatform.i +++ lldb/bindings/interface/SBPlatform.i @@ -194,6 +194,9 @@ lldb::SBUnixSignals GetUnixSignals(); + lldb::SBEnvironment + GetEnvironment(); + }; } // namespace lldb Index: lldb/bindings/interface/SBEnvironment.i =================================================================== --- /dev/null +++ lldb/bindings/interface/SBEnvironment.i @@ -0,0 +1,40 @@ +//===-- SWIG Interface for SBEnvironment-------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"Represents the environment of a certain process. + +Example: + for entry in lldb.debugger.GetSelectedTarget().GetEnvironment().GetEntries(): + print(entry) + +") SBEnvironment; +class SBEnvironment { +public: + SBEnvironment (); + + SBEnvironment (const lldb::SBEnvironment &rhs); + + ~SBEnvironment(); + + size_t GetNumValues(); + + const char *Get(const char *name); + + const char *GetNameAtIndex(size_t index); + + const char *GetValueAtIndex(size_t index); + + bool Set(const char *name, const char *value, bool overwrite); + + bool Unset(const char *name); +}; + +} // namespace lldb Index: lldb/bindings/headers.swig =================================================================== --- lldb/bindings/headers.swig +++ lldb/bindings/headers.swig @@ -21,6 +21,7 @@ #include "lldb/API/SBData.h" #include "lldb/API/SBDebugger.h" #include "lldb/API/SBDeclaration.h" +#include "lldb/API/SBEnvironment.h" #include "lldb/API/SBError.h" #include "lldb/API/SBEvent.h" #include "lldb/API/SBExecutionContext.h"
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits