[Lldb-commits] [lldb] Add the ability to look up persistent types and variables defined in the expression parser through the SB API's. (PR #203128)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Jun 15 16:46:39 PDT 2026
https://github.com/jimingham updated https://github.com/llvm/llvm-project/pull/203128
>From e44cadf82148e1953097516747c85d30a042f4ef Mon Sep 17 00:00:00 2001
From: Jim Ingham <jingham at apple.com>
Date: Wed, 10 Jun 2026 16:47:05 -0700
Subject: [PATCH 1/4] Add the ability to look up persistent types and variables
defined in the expression parser through the SB API's.
---
lldb/bindings/interface/SBTargetDocstrings.i | 30 +++++
lldb/include/lldb/API/SBTarget.h | 6 +
lldb/source/API/SBTarget.cpp | 85 ++++++++++++++
.../API/python_api/persistent_decls/Makefile | 4 +
.../persistent_decls/TestPersistentDecls.py | 111 ++++++++++++++++++
.../API/python_api/persistent_decls/main.c | 6 +
6 files changed, 242 insertions(+)
create mode 100644 lldb/test/API/python_api/persistent_decls/Makefile
create mode 100644 lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
create mode 100644 lldb/test/API/python_api/persistent_decls/main.c
diff --git a/lldb/bindings/interface/SBTargetDocstrings.i b/lldb/bindings/interface/SBTargetDocstrings.i
index b486a8f189f10..3cfb18f766cd2 100644
--- a/lldb/bindings/interface/SBTargetDocstrings.i
+++ b/lldb/bindings/interface/SBTargetDocstrings.i
@@ -307,6 +307,36 @@ produces: ::
An SBAddress which will be valid if..."
) lldb::SBTarget::ResolveFileAddress;
+%feature("docstring", "
+ Look up a persistent type defined using the expression parser.
+
+ @param[in] type_name
+ The base name of the persistent type you defined.
+
+ @param[in] language
+ A member of the enum lldb::LanguageType giving the
+ language of the Expression parser you used to define
+ the persistent type.
+
+ @return
+ An SBType representing the persistent type you defined."
+) lldb::SBTarget::FindExpressionTypeForLanguage;
+
+%feature("docstring", "
+ Look up a persistent variable defined using the expression parser.
+
+ @param[in] variable_name
+ The name of the persistent variable you defined.
+
+ @param[in] language
+ A member of the enum lldb::LanguageType giving the
+ language of the Expression parser you used to define
+ the persistent type.
+
+ @return
+ An SBValue representing the persistent variable you defined."
+) lldb::SBTarget::FindExpressionVariableForLanguage;
+
%feature("docstring", "
Read target memory. If a target process is running then memory
is read from here. Otherwise the memory is read from the object
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index d598c44dd7332..113c5db0331df 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -923,6 +923,12 @@ class LLDB_API SBTarget {
lldb::SBType GetBasicType(lldb::BasicType type);
+ lldb::SBType FindExpressionTypeForLanguage(const char *typename_cstr,
+ lldb::LanguageType lang);
+
+ lldb::SBValue FindExpressionVariableForLanguage(const char *varname_cstr,
+ lldb::LanguageType lang);
+
lldb::SBValue CreateValueFromAddress(const char *name, lldb::SBAddress addr,
lldb::SBType type);
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 72286336102d2..9ac6f06c9b840 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -40,6 +40,7 @@
#include "lldb/Core/SearchFilter.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StructuredDataImpl.h"
+#include "lldb/Expression/ExpressionVariable.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h"
#include "lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h"
@@ -1878,6 +1879,90 @@ lldb::SBSymbolContextList SBTarget::FindGlobalFunctions(const char *name,
return sb_sc_list;
}
+lldb::SBType SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
+ lldb::LanguageType language) {
+ TargetSP target_sp = GetSP();
+ if (!target_sp)
+ return {};
+
+ if (!typename_cstr || !typename_cstr[0])
+ return {};
+
+ ConstString const_typename(typename_cstr);
+
+ // If the language type was "unknown" search all languages:
+ if (language == lldb::eLanguageTypeUnknown) {
+ LanguageSet expr_languages =
+ Language::GetLanguagesSupportingTypeSystemsForExpressions();
+ for (int bit : expr_languages.bitvector.set_bits()) {
+ auto cur_lang = (LanguageType)bit;
+ PersistentExpressionState *persistent =
+ target_sp->GetPersistentExpressionStateForLanguage(cur_lang);
+ if (persistent) {
+ std::optional<CompilerType> type_op
+ = persistent->GetCompilerTypeFromPersistentDecl(const_typename);
+ if (type_op) {
+ return SBType(*type_op);
+ }
+ }
+ }
+ } else {
+ PersistentExpressionState *persistent =
+ target_sp->GetPersistentExpressionStateForLanguage(language);
+ if (persistent) {
+ std::optional<CompilerType> type_op
+ = persistent->GetCompilerTypeFromPersistentDecl(const_typename);
+ if (type_op && (*type_op)) {
+ return SBType(*type_op);
+ }
+ }
+ }
+ return {};
+}
+
+lldb::SBValue SBTarget::FindExpressionVariableForLanguage(
+ const char *varname_cstr, lldb::LanguageType language) {
+ TargetSP target_sp = GetSP();
+ if (!target_sp)
+ return {};
+
+ if (!varname_cstr || !varname_cstr[0])
+ return {};
+
+ ConstString const_varname(varname_cstr);
+
+ // If the language type was "unknown" search all languages:
+ if (language == lldb::eLanguageTypeUnknown) {
+ LanguageSet expr_languages =
+ Language::GetLanguagesSupportingTypeSystemsForExpressions();
+ for (int bit : expr_languages.bitvector.set_bits()) {
+ auto cur_lang = (LanguageType)bit;
+ PersistentExpressionState *persistent =
+ target_sp->GetPersistentExpressionStateForLanguage(cur_lang);
+ if (persistent) {
+ lldb::ExpressionVariableSP expr_var_sp =
+ persistent->GetVariable(const_varname);
+ if (expr_var_sp) {
+ return expr_var_sp->GetValueObject();
+ }
+ }
+ }
+ } else {
+ PersistentExpressionState *persistent =
+ target_sp->GetPersistentExpressionStateForLanguage(language);
+ if (persistent) {
+ lldb::ExpressionVariableSP expr_var_sp =
+ persistent->GetVariable(const_varname);
+ if (expr_var_sp) {
+ return expr_var_sp->GetValueObject();
+ }
+ }
+ }
+ return {};
+}
+
+
+
lldb::SBType SBTarget::FindFirstType(const char *typename_cstr) {
LLDB_INSTRUMENT_VA(this, typename_cstr);
diff --git a/lldb/test/API/python_api/persistent_decls/Makefile b/lldb/test/API/python_api/persistent_decls/Makefile
new file mode 100644
index 0000000000000..695335e068c0c
--- /dev/null
+++ b/lldb/test/API/python_api/persistent_decls/Makefile
@@ -0,0 +1,4 @@
+C_SOURCES := main.c
+CFLAGS_EXTRAS := -std=c99
+
+include Makefile.rules
diff --git a/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
new file mode 100644
index 0000000000000..1381a251bb9a8
--- /dev/null
+++ b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
@@ -0,0 +1,111 @@
+"""
+Test the SBTarget API's to retrieve persistent types
+and values.
+"""
+
+
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+
+
+class TestPersistentDecls(TestBase):
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def test_persistent_types(self):
+ """Define some types in the expression evaluator and find them."""
+ self.build()
+ self.main_source_file = lldb.SBFileSpec("main.c")
+ self.types_test(False)
+
+ def test_persistent_types_unknown(self):
+ """Define some types in the expression evaluator and find them."""
+ self.build()
+ self.main_source_file = lldb.SBFileSpec("main.c")
+ self.types_test(True)
+
+ def test_persistent_values(self):
+ """Define some values in the expression evaluator and find them."""
+ self.build()
+ self.main_source_file = lldb.SBFileSpec("main.c")
+ self.values_test(False)
+
+ def test_persistent_values_unknown(self):
+ """Define some values in the expression evaluator and find them."""
+ self.build()
+ self.main_source_file = lldb.SBFileSpec("main.c")
+ self.values_test(True)
+
+ def types_test(self, use_unknown):
+ (target, _, _, _) = lldbutil.run_to_source_breakpoint(
+ self, "Set a breakpoint here", self.main_source_file
+ )
+
+ # Make some types so we aren't succeeding in gettting the only one.
+
+ typename = "$firstStruct"
+
+ self.expect(f"expr struct $SomeType {{ int b; int a; int c;}}")
+ self.expect(f"expr struct {typename} {{ int a; int b; char *c;}}")
+ self.expect(f"expr struct $AnotherType {{ int a; char *b; int c;}}")
+ self.expect(f"expr struct $YetAnotherType {{ char *a; int b; int c;}}")
+
+ if use_unknown:
+ language = lldb.eLanguageTypeUnknown
+ else:
+ language = lldb.eLanguageTypeC_plus_plus
+
+ type = target.FindExpressionTypeForLanguage(typename, language)
+ self.assertTrue(type.IsValid(), "Got a valid type")
+
+ # Make sure we got the type we expected:
+ self.assertEqual(type.name, typename, "Got the right type.")
+ # Now check that the fields are right:
+ self.assertEqual(type.num_fields, 3, "Right number of fields")
+
+ ivar_a = type.fields[0]
+ self.assertEqual(ivar_a.name, "a", "a name is right")
+ self.assertEqual(ivar_a.type.name, "int", "Right type")
+
+ ivar_b = type.fields[1]
+ self.assertEqual(ivar_b.name, "b", "b name is right")
+ self.assertEqual(ivar_b.type.name, "int", "Right type")
+
+ ivar_c = type.fields[2]
+ self.assertEqual(ivar_c.name, "c", "c name is right")
+ self.assertEqual(ivar_c.type.name, "char *", "Right type")
+
+ def values_test(self, use_unknown):
+ (target, _, _, _) = lldbutil.run_to_source_breakpoint(
+ self, "Set a breakpoint here", self.main_source_file
+ )
+
+ type_name = "struct $MyStruct"
+ value_name = "$my_struct"
+ self.expect("expr int $my_int = 100")
+ self.expect('expr char *$my_char_ptr = "Some char pointer."')
+ self.expect(f"expr {type_name} {{int a; int b;}}; {type_name} {value_name} = {{10, 20}}")
+
+ # Now try to find one:
+ if use_unknown:
+ language = lldb.eLanguageTypeUnknown
+ else:
+ language = lldb.eLanguageTypeC_plus_plus
+
+ value = target.FindExpressionVariableForLanguage(
+ value_name,
+ language
+ )
+
+ self.assertTrue(value.IsValid(), "Got a valid SBValue")
+ self.assertTrue(value.GetError().Success(), "Got a value")
+
+ value_checker = ValueCheck(
+ name=value_name,
+ type=type_name,
+ children=[
+ ValueCheck(name="a", type="int", value='10'),
+ ValueCheck(name="b", type="int", value='20')
+ ]
+ )
+ value_checker.check_value(self, value, "Found the right value")
diff --git a/lldb/test/API/python_api/persistent_decls/main.c b/lldb/test/API/python_api/persistent_decls/main.c
new file mode 100644
index 0000000000000..31280778072e3
--- /dev/null
+++ b/lldb/test/API/python_api/persistent_decls/main.c
@@ -0,0 +1,6 @@
+int
+main()
+{
+ int test_var = 10; // Set a breakpoint here
+ return test_var;
+}
>From 5796a6c8a8abc5bbcaa9187da3b0a73ffeac15ba Mon Sep 17 00:00:00 2001
From: Jim Ingham <jingham at apple.com>
Date: Thu, 11 Jun 2026 14:58:17 -0700
Subject: [PATCH 2/4] Formatting
---
lldb/include/lldb/API/SBTarget.h | 4 +--
lldb/source/API/SBTarget.cpp | 20 +++++++--------
.../persistent_decls/TestPersistentDecls.py | 25 +++++++++----------
.../API/python_api/persistent_decls/main.c | 4 +--
4 files changed, 25 insertions(+), 28 deletions(-)
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 113c5db0331df..c9e04a5a2ec57 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -924,10 +924,10 @@ class LLDB_API SBTarget {
lldb::SBType GetBasicType(lldb::BasicType type);
lldb::SBType FindExpressionTypeForLanguage(const char *typename_cstr,
- lldb::LanguageType lang);
+ lldb::LanguageType lang);
lldb::SBValue FindExpressionVariableForLanguage(const char *varname_cstr,
- lldb::LanguageType lang);
+ lldb::LanguageType lang);
lldb::SBValue CreateValueFromAddress(const char *name, lldb::SBAddress addr,
lldb::SBType type);
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 9ac6f06c9b840..cb2c0fc482a34 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1879,8 +1879,9 @@ lldb::SBSymbolContextList SBTarget::FindGlobalFunctions(const char *name,
return sb_sc_list;
}
-lldb::SBType SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
- lldb::LanguageType language) {
+lldb::SBType
+SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
+ lldb::LanguageType language) {
TargetSP target_sp = GetSP();
if (!target_sp)
return {};
@@ -1899,8 +1900,8 @@ lldb::SBType SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
PersistentExpressionState *persistent =
target_sp->GetPersistentExpressionStateForLanguage(cur_lang);
if (persistent) {
- std::optional<CompilerType> type_op
- = persistent->GetCompilerTypeFromPersistentDecl(const_typename);
+ std::optional<CompilerType> type_op =
+ persistent->GetCompilerTypeFromPersistentDecl(const_typename);
if (type_op) {
return SBType(*type_op);
}
@@ -1910,8 +1911,8 @@ lldb::SBType SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
PersistentExpressionState *persistent =
target_sp->GetPersistentExpressionStateForLanguage(language);
if (persistent) {
- std::optional<CompilerType> type_op
- = persistent->GetCompilerTypeFromPersistentDecl(const_typename);
+ std::optional<CompilerType> type_op =
+ persistent->GetCompilerTypeFromPersistentDecl(const_typename);
if (type_op && (*type_op)) {
return SBType(*type_op);
}
@@ -1920,8 +1921,9 @@ lldb::SBType SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
return {};
}
-lldb::SBValue SBTarget::FindExpressionVariableForLanguage(
- const char *varname_cstr, lldb::LanguageType language) {
+lldb::SBValue
+SBTarget::FindExpressionVariableForLanguage(const char *varname_cstr,
+ lldb::LanguageType language) {
TargetSP target_sp = GetSP();
if (!target_sp)
return {};
@@ -1961,8 +1963,6 @@ lldb::SBValue SBTarget::FindExpressionVariableForLanguage(
return {};
}
-
-
lldb::SBType SBTarget::FindFirstType(const char *typename_cstr) {
LLDB_INSTRUMENT_VA(this, typename_cstr);
diff --git a/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
index 1381a251bb9a8..e41b314a2bf94 100644
--- a/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
+++ b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
@@ -29,20 +29,20 @@ def test_persistent_values(self):
self.build()
self.main_source_file = lldb.SBFileSpec("main.c")
self.values_test(False)
-
+
def test_persistent_values_unknown(self):
"""Define some values in the expression evaluator and find them."""
self.build()
self.main_source_file = lldb.SBFileSpec("main.c")
self.values_test(True)
-
+
def types_test(self, use_unknown):
(target, _, _, _) = lldbutil.run_to_source_breakpoint(
self, "Set a breakpoint here", self.main_source_file
)
# Make some types so we aren't succeeding in gettting the only one.
-
+
typename = "$firstStruct"
self.expect(f"expr struct $SomeType {{ int b; int a; int c;}}")
@@ -54,7 +54,7 @@ def types_test(self, use_unknown):
language = lldb.eLanguageTypeUnknown
else:
language = lldb.eLanguageTypeC_plus_plus
-
+
type = target.FindExpressionTypeForLanguage(typename, language)
self.assertTrue(type.IsValid(), "Got a valid type")
@@ -84,7 +84,9 @@ def values_test(self, use_unknown):
value_name = "$my_struct"
self.expect("expr int $my_int = 100")
self.expect('expr char *$my_char_ptr = "Some char pointer."')
- self.expect(f"expr {type_name} {{int a; int b;}}; {type_name} {value_name} = {{10, 20}}")
+ self.expect(
+ f"expr {type_name} {{int a; int b;}}; {type_name} {value_name} = {{10, 20}}"
+ )
# Now try to find one:
if use_unknown:
@@ -92,11 +94,8 @@ def values_test(self, use_unknown):
else:
language = lldb.eLanguageTypeC_plus_plus
- value = target.FindExpressionVariableForLanguage(
- value_name,
- language
- )
-
+ value = target.FindExpressionVariableForLanguage(value_name, language)
+
self.assertTrue(value.IsValid(), "Got a valid SBValue")
self.assertTrue(value.GetError().Success(), "Got a value")
@@ -104,8 +103,8 @@ def values_test(self, use_unknown):
name=value_name,
type=type_name,
children=[
- ValueCheck(name="a", type="int", value='10'),
- ValueCheck(name="b", type="int", value='20')
- ]
+ ValueCheck(name="a", type="int", value="10"),
+ ValueCheck(name="b", type="int", value="20"),
+ ],
)
value_checker.check_value(self, value, "Found the right value")
diff --git a/lldb/test/API/python_api/persistent_decls/main.c b/lldb/test/API/python_api/persistent_decls/main.c
index 31280778072e3..001333e92d9bf 100644
--- a/lldb/test/API/python_api/persistent_decls/main.c
+++ b/lldb/test/API/python_api/persistent_decls/main.c
@@ -1,6 +1,4 @@
-int
-main()
-{
+int main() {
int test_var = 10; // Set a breakpoint here
return test_var;
}
>From 58a542486507882b4614fd883969d68597380c09 Mon Sep 17 00:00:00 2001
From: Jim Ingham <jingham at apple.com>
Date: Mon, 15 Jun 2026 16:18:52 -0700
Subject: [PATCH 3/4] Don't use eLanguageTypeUnknown to search all languages.
There is only one possible variable/type per language, so I wanted to
preserve the convenience of not having to go through a list to get the one
thing it can hold. And if you want to iterate over languages, that's easy to
do from the outside. I was logging LanguageTypes a bunch and that got
annoying so I also added a formatv adaptor for LanguageType.
---
lldb/include/lldb/API/SBTarget.h | 3 +-
lldb/include/lldb/Target/Language.h | 9 ++
lldb/source/API/SBTarget.cpp | 118 +++++++++---------
lldb/source/Target/Language.cpp | 6 +
.../persistent_decls/TestPersistentDecls.py | 57 +++++----
5 files changed, 108 insertions(+), 85 deletions(-)
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index c9e04a5a2ec57..1c1bb1b501a0f 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -924,7 +924,8 @@ class LLDB_API SBTarget {
lldb::SBType GetBasicType(lldb::BasicType type);
lldb::SBType FindExpressionTypeForLanguage(const char *typename_cstr,
- lldb::LanguageType lang);
+ lldb::LanguageType lang,
+ SBError &error);
lldb::SBValue FindExpressionVariableForLanguage(const char *varname_cstr,
lldb::LanguageType lang);
diff --git a/lldb/include/lldb/Target/Language.h b/lldb/include/lldb/Target/Language.h
index 9205b5e339977..5987ae373936f 100644
--- a/lldb/include/lldb/Target/Language.h
+++ b/lldb/include/lldb/Target/Language.h
@@ -24,6 +24,8 @@
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/lldb-private.h"
#include "lldb/lldb-public.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatVariadic.h"
namespace lldb_private {
@@ -519,4 +521,11 @@ class Language : public PluginInterface {
} // namespace lldb_private
+namespace llvm {
+ template <> struct format_provider<lldb::LanguageType> {
+ static void format(const lldb::LanguageType &language, llvm::raw_ostream &OS,
+ llvm::StringRef Options);
+};
+} // namespace llvm
+
#endif // LLDB_TARGET_LANGUAGE_H
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index cb2c0fc482a34..98525fd684eed 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1881,43 +1881,47 @@ lldb::SBSymbolContextList SBTarget::FindGlobalFunctions(const char *name,
lldb::SBType
SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
- lldb::LanguageType language) {
+ lldb::LanguageType language,
+ SBError &sb_error) {
+ sb_error.Clear();
+
TargetSP target_sp = GetSP();
- if (!target_sp)
+ if (!target_sp) {
+ sb_error.SetErrorString("no target.");
return {};
+ }
- if (!typename_cstr || !typename_cstr[0])
+ if (!typename_cstr || !typename_cstr[0]) {
+ sb_error.SetErrorString("empty type name for search.");
return {};
+ }
+
+ if (language == eLanguageTypeUnknown) {
+ sb_error.SetErrorString("eLanguageTypeUnknown can't define expression "
+ "types.");
+ return {};
+ }
ConstString const_typename(typename_cstr);
- // If the language type was "unknown" search all languages:
- if (language == lldb::eLanguageTypeUnknown) {
- LanguageSet expr_languages =
- Language::GetLanguagesSupportingTypeSystemsForExpressions();
- for (int bit : expr_languages.bitvector.set_bits()) {
- auto cur_lang = (LanguageType)bit;
- PersistentExpressionState *persistent =
- target_sp->GetPersistentExpressionStateForLanguage(cur_lang);
- if (persistent) {
- std::optional<CompilerType> type_op =
- persistent->GetCompilerTypeFromPersistentDecl(const_typename);
- if (type_op) {
- return SBType(*type_op);
- }
- }
- }
- } else {
- PersistentExpressionState *persistent =
- target_sp->GetPersistentExpressionStateForLanguage(language);
- if (persistent) {
- std::optional<CompilerType> type_op =
- persistent->GetCompilerTypeFromPersistentDecl(const_typename);
- if (type_op && (*type_op)) {
- return SBType(*type_op);
- }
- }
+ PersistentExpressionState *persistent =
+ target_sp->GetPersistentExpressionStateForLanguage(language);
+
+ if (!persistent) {
+ sb_error.SetErrorString(llvm::formatv(
+ "language {0} does not support expression defined types",
+ language).str().c_str());
+ return {};
}
+
+ std::optional<CompilerType> type_op =
+ persistent->GetCompilerTypeFromPersistentDecl(const_typename);
+ if (type_op && (*type_op)) {
+ return SBType(*type_op);
+ }
+ sb_error.SetErrorString(llvm::formatv(
+ "no type {0} found in expression types for language {1}",
+ typename_cstr, language).str().c_str());
return {};
}
@@ -1926,41 +1930,41 @@ SBTarget::FindExpressionVariableForLanguage(const char *varname_cstr,
lldb::LanguageType language) {
TargetSP target_sp = GetSP();
if (!target_sp)
- return {};
+ return ValueObjectConstResult::Create(nullptr,
+ Status::FromErrorStringWithFormatv(
+ "no variable {0} found for language {1}",
+ varname_cstr, language));
+
if (!varname_cstr || !varname_cstr[0])
- return {};
+ return ValueObjectConstResult::Create(target_sp.get(),
+ Status::FromErrorString("empty variable name for search."));
+
+ if (language == eLanguageTypeUnknown)
+ return ValueObjectConstResult::Create(nullptr,
+ Status::FromErrorStringWithFormatv(
+ "eLanguageTypeUnknown doesn't support expression variables.",
+ varname_cstr, language));
ConstString const_varname(varname_cstr);
- // If the language type was "unknown" search all languages:
- if (language == lldb::eLanguageTypeUnknown) {
- LanguageSet expr_languages =
- Language::GetLanguagesSupportingTypeSystemsForExpressions();
- for (int bit : expr_languages.bitvector.set_bits()) {
- auto cur_lang = (LanguageType)bit;
- PersistentExpressionState *persistent =
- target_sp->GetPersistentExpressionStateForLanguage(cur_lang);
- if (persistent) {
- lldb::ExpressionVariableSP expr_var_sp =
- persistent->GetVariable(const_varname);
- if (expr_var_sp) {
- return expr_var_sp->GetValueObject();
- }
- }
- }
- } else {
- PersistentExpressionState *persistent =
+ PersistentExpressionState *persistent =
target_sp->GetPersistentExpressionStateForLanguage(language);
- if (persistent) {
- lldb::ExpressionVariableSP expr_var_sp =
- persistent->GetVariable(const_varname);
- if (expr_var_sp) {
- return expr_var_sp->GetValueObject();
- }
- }
+ if (!persistent) {
+ return ValueObjectConstResult::Create(target_sp.get(),
+ Status::FromErrorStringWithFormatv(
+ "language: {0} doesn't support expression variables.", language));
}
- return {};
+
+ lldb::ExpressionVariableSP expr_var_sp =
+ persistent->GetVariable(const_varname);
+ if (expr_var_sp)
+ return expr_var_sp->GetValueObject();
+
+ return ValueObjectConstResult::Create(target_sp.get(),
+ Status::FromErrorStringWithFormatv(
+ "no variable {0} found for language {1}", varname_cstr, language));
+
}
lldb::SBType SBTarget::FindFirstType(const char *typename_cstr) {
diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp
index 03754e988faa4..077c403f4ea58 100644
--- a/lldb/source/Target/Language.cpp
+++ b/lldb/source/Target/Language.cpp
@@ -631,3 +631,9 @@ bool SourceLanguage::IsObjC() const {
bool SourceLanguage::IsCPlusPlus() const {
return name == llvm::dwarf::DW_LNAME_C_plus_plus;
}
+
+void llvm::format_provider<lldb::LanguageType>::format(
+ const lldb::LanguageType &language, llvm::raw_ostream &OS,
+ llvm::StringRef Options) {
+ OS << Language::GetNameForLanguageType(language);
+}
diff --git a/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
index e41b314a2bf94..531366a3e96be 100644
--- a/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
+++ b/lldb/test/API/python_api/persistent_decls/TestPersistentDecls.py
@@ -16,27 +16,15 @@ def test_persistent_types(self):
"""Define some types in the expression evaluator and find them."""
self.build()
self.main_source_file = lldb.SBFileSpec("main.c")
- self.types_test(False)
-
- def test_persistent_types_unknown(self):
- """Define some types in the expression evaluator and find them."""
- self.build()
- self.main_source_file = lldb.SBFileSpec("main.c")
- self.types_test(True)
+ self.types_test()
def test_persistent_values(self):
"""Define some values in the expression evaluator and find them."""
self.build()
self.main_source_file = lldb.SBFileSpec("main.c")
- self.values_test(False)
-
- def test_persistent_values_unknown(self):
- """Define some values in the expression evaluator and find them."""
- self.build()
- self.main_source_file = lldb.SBFileSpec("main.c")
- self.values_test(True)
+ self.values_test()
- def types_test(self, use_unknown):
+ def types_test(self):
(target, _, _, _) = lldbutil.run_to_source_breakpoint(
self, "Set a breakpoint here", self.main_source_file
)
@@ -50,12 +38,10 @@ def types_test(self, use_unknown):
self.expect(f"expr struct $AnotherType {{ int a; char *b; int c;}}")
self.expect(f"expr struct $YetAnotherType {{ char *a; int b; int c;}}")
- if use_unknown:
- language = lldb.eLanguageTypeUnknown
- else:
- language = lldb.eLanguageTypeC_plus_plus
-
- type = target.FindExpressionTypeForLanguage(typename, language)
+ language = lldb.eLanguageTypeC_plus_plus
+ error = lldb.SBError()
+ type = target.FindExpressionTypeForLanguage(typename, language, error)
+ self.assertSuccess(error, "Got the right error")
self.assertTrue(type.IsValid(), "Got a valid type")
# Make sure we got the type we expected:
@@ -75,7 +61,18 @@ def types_test(self, use_unknown):
self.assertEqual(ivar_c.name, "c", "c name is right")
self.assertEqual(ivar_c.type.name, "char *", "Right type")
- def values_test(self, use_unknown):
+ # Also test the error returns:
+ #type = target.FindExpressionTypeForLanguage(typename, lldb.eLanguageTypeUnknown, error)
+ #self.assertFalse(error, "unknown doesn't support expression types")
+ #self.assertFalse(type.IsValid(), "Type is also invalid.")
+ type = target.FindExpressionTypeForLanguage("", language, error)
+ self.assertFalse(error.Success(), "empty type name for search.")
+ self.assertFalse(type.IsValid(), "Type is also invalid.")
+ type = target.FindExpressionTypeForLanguage("doesnt_start_with_dollar", language, error)
+ self.assertFalse(error.Success(), "Can't find names that don't exist.")
+ self.assertFalse(type.IsValid(), "Type is also invalid.")
+
+ def values_test(self):
(target, _, _, _) = lldbutil.run_to_source_breakpoint(
self, "Set a breakpoint here", self.main_source_file
)
@@ -89,15 +86,12 @@ def values_test(self, use_unknown):
)
# Now try to find one:
- if use_unknown:
- language = lldb.eLanguageTypeUnknown
- else:
- language = lldb.eLanguageTypeC_plus_plus
+ language = lldb.eLanguageTypeC_plus_plus
value = target.FindExpressionVariableForLanguage(value_name, language)
self.assertTrue(value.IsValid(), "Got a valid SBValue")
- self.assertTrue(value.GetError().Success(), "Got a value")
+ self.assertSuccess(value.GetError(), "Got no errors")
value_checker = ValueCheck(
name=value_name,
@@ -108,3 +102,12 @@ def values_test(self, use_unknown):
],
)
value_checker.check_value(self, value, "Found the right value")
+
+ # Also test that errors are set correctly:
+ value = target.FindExpressionVariableForLanguage(value_name, lldb.eLanguageTypeUnknown)
+ self.assertFalse(value.error.Success(), "unknown can't compile expressions")
+ value = target.FindExpressionVariableForLanguage(None, language)
+ self.assertFalse(value.error.Success(), "reject empty expression variable name")
+ value = target.FindExpressionVariableForLanguage("doesnt_start_with_dollar", language)
+ self.assertFalse(value.error.Success(), "error on unknown variable name")
+
>From d4f944aacde4d2947b3eb651341f5880d6597a44 Mon Sep 17 00:00:00 2001
From: Jim Ingham <jingham at apple.com>
Date: Mon, 15 Jun 2026 16:45:42 -0700
Subject: [PATCH 4/4] Add LLDB_INSTRUMENT_VA macros to SBTarget additions.
---
lldb/source/API/SBTarget.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 98525fd684eed..356279513ac7a 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -1883,6 +1883,7 @@ lldb::SBType
SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
lldb::LanguageType language,
SBError &sb_error) {
+ LLDB_INSTRUMENT_VA(this, typename_cstr, language, sb_error);
sb_error.Clear();
TargetSP target_sp = GetSP();
@@ -1928,6 +1929,7 @@ SBTarget::FindExpressionTypeForLanguage(const char *typename_cstr,
lldb::SBValue
SBTarget::FindExpressionVariableForLanguage(const char *varname_cstr,
lldb::LanguageType language) {
+ LLDB_INSTRUMENT_VA(this, varname_cstr, language);
TargetSP target_sp = GetSP();
if (!target_sp)
return ValueObjectConstResult::Create(nullptr,
More information about the lldb-commits
mailing list