Skip to content

Commit

Permalink
Add a new SBExpressionOptions::SetLanguage() API (NFCI)
Browse files Browse the repository at this point in the history
that separates out language and version. To avoid reinventing the
wheel and introducing subtle incompatibilities, this API uses the
table of languages and versiond defined by the upcoming DWARF 6
standard (https://dwarfstd.org/languages-v6.html). While the DWARF 6
spec is not finialized, the list of languages is broadly considered
stable.

The primary motivation for this is to allow the Swift language plugin
to switch between language dialects between, e.g., Swift 5.9 and 6.0
with out introducing a ton of new language codes. On the main branch
this change is considered NFC.
  • Loading branch information
adrian-prantl committed Apr 26, 2024
1 parent 300340f commit aba61b2
Show file tree
Hide file tree
Showing 36 changed files with 272 additions and 116 deletions.
13 changes: 13 additions & 0 deletions lldb/include/lldb/API/SBExpressionOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@

namespace lldb {

/// Programming language type.
///
/// These enumerations use the same language enumerations as the DWARF
/// specification for ease of use and consistency.
enum SBSourceLanguageName : uint16_t {
#define HANDLE_DW_LNAME(ID, NAME, DESC, LOWER_BOUND) eLanguageName##NAME = ID,
#include "lldb/API/Languages.h"
};

class LLDB_API SBExpressionOptions {
public:
SBExpressionOptions();
Expand Down Expand Up @@ -67,6 +76,10 @@ class LLDB_API SBExpressionOptions {
void SetTrapExceptions(bool trap_exceptions = true);

void SetLanguage(lldb::LanguageType language);
/// Set the language using a pair of language code and version as
/// defined by the DWARF 6 specification.
/// WARNING: These codes may change until DWARF 6 is finalized.
void SetLanguage(uint16_t dwarf_lname_code, uint32_t dwarf_lversion);

#ifndef SWIG
void SetCancelCallback(lldb::ExpressionCancelCallback callback, void *baton);
Expand Down
7 changes: 2 additions & 5 deletions lldb/include/lldb/Expression/Expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,8 @@ class Expression {
/// expression. Text() should contain the definition of this function.
virtual const char *FunctionName() = 0;

/// Return the language that should be used when parsing. To use the
/// default, return eLanguageTypeUnknown.
virtual lldb::LanguageType Language() const {
return lldb::eLanguageTypeUnknown;
}
/// Return the language that should be used when parsing.
virtual SourceLanguage Language() const { return {}; }

/// Return the Materializer that the parser should use when registering
/// external values.
Expand Down
2 changes: 1 addition & 1 deletion lldb/include/lldb/Expression/LLVMUserExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class LLVMUserExpression : public UserExpression {
};

LLVMUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr,
llvm::StringRef prefix, lldb::LanguageType language,
llvm::StringRef prefix, SourceLanguage language,
ResultType desired_type,
const EvaluateExpressionOptions &options);
~LLVMUserExpression() override;
Expand Down
33 changes: 18 additions & 15 deletions lldb/include/lldb/Expression/UserExpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class UserExpression : public Expression {
/// If not eResultTypeAny, the type to use for the expression
/// result.
UserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr,
llvm::StringRef prefix, lldb::LanguageType language,
llvm::StringRef prefix, SourceLanguage language,
ResultType desired_type,
const EvaluateExpressionOptions &options);

Expand Down Expand Up @@ -202,7 +202,7 @@ class UserExpression : public Expression {
virtual bool IsParseCacheable() { return true; }
/// Return the language that should be used when parsing. To use the
/// default, return eLanguageTypeUnknown.
lldb::LanguageType Language() const override { return m_language; }
SourceLanguage Language() const override { return m_language; }

/// Return the desired result type of the function, or eResultTypeAny if
/// indifferent.
Expand Down Expand Up @@ -315,19 +315,22 @@ class UserExpression : public Expression {
lldb::ProcessSP &process_sp,
lldb::StackFrameSP &frame_sp);

Address m_address; ///< The address the process is stopped in.
std::string m_expr_text; ///< The text of the expression, as typed by the user
std::string m_expr_prefix; ///< The text of the translation-level definitions,
///as provided by the user
std::string m_fixed_text; ///< The text of the expression with fix-its applied
///- this won't be set if the fixed text doesn't
///parse.
lldb::LanguageType m_language; ///< The language to use when parsing
///(eLanguageTypeUnknown means use defaults)
ResultType m_desired_type; ///< The type to coerce the expression's result to.
///If eResultTypeAny, inferred from the expression.
EvaluateExpressionOptions
m_options; ///< Additional options provided by the user.
/// The address the process is stopped in.
Address m_address;
/// The text of the expression, as typed by the user.
std::string m_expr_text;
/// The text of the translation-level definitions, as provided by the user.
std::string m_expr_prefix;
/// The text of the expression with fix-its applied this won't be set if the
/// fixed text doesn't parse.
std::string m_fixed_text;
/// The language to use when parsing (unknown means use defaults).
SourceLanguage m_language;
/// The type to coerce the expression's result to. If eResultTypeAny, inferred
/// from the expression.
ResultType m_desired_type;
/// Additional options provided by the user.
EvaluateExpressionOptions m_options;
};

} // namespace lldb_private
Expand Down
10 changes: 4 additions & 6 deletions lldb/include/lldb/Symbol/TypeSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -483,12 +483,10 @@ class TypeSystem : public PluginInterface,
return IsPointerOrReferenceType(type, nullptr);
}

virtual UserExpression *
GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix,
lldb::LanguageType language,
Expression::ResultType desired_type,
const EvaluateExpressionOptions &options,
ValueObject *ctx_obj) {
virtual UserExpression *GetUserExpression(
llvm::StringRef expr, llvm::StringRef prefix, SourceLanguage language,
Expression::ResultType desired_type,
const EvaluateExpressionOptions &options, ValueObject *ctx_obj) {
return nullptr;
}

Expand Down
11 changes: 5 additions & 6 deletions lldb/include/lldb/Target/StackFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,13 +446,12 @@ class StackFrame : public ExecutionContextScope,
/// Query this frame to determine what the default language should be when
/// parsing expressions given the execution context.
///
/// \return
/// The language of the frame if known, else lldb::eLanguageTypeUnknown.
lldb::LanguageType GetLanguage();
/// \return The language of the frame if known.
SourceLanguage GetLanguage();

// similar to GetLanguage(), but is allowed to take a potentially incorrect
// guess if exact information is not available
lldb::LanguageType GuessLanguage();
/// Similar to GetLanguage(), but is allowed to take a potentially incorrect
/// guess if exact information is not available
SourceLanguage GuessLanguage();

/// Attempt to econstruct the ValueObject for a given raw address touched by
/// the current instruction. The ExpressionPath should indicate how to get
Expand Down
19 changes: 14 additions & 5 deletions lldb/include/lldb/Target/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ class TargetProperties : public Properties {

bool GetBreakpointsConsultPlatformAvoidList();

lldb::LanguageType GetLanguage() const;
SourceLanguage GetLanguage() const;

llvm::StringRef GetExpressionPrefixContents();

Expand Down Expand Up @@ -310,9 +310,18 @@ class EvaluateExpressionOptions {
m_execution_policy = policy;
}

lldb::LanguageType GetLanguage() const { return m_language; }
SourceLanguage GetLanguage() const { return m_language; }

void SetLanguage(lldb::LanguageType language) { m_language = language; }
void SetLanguage(lldb::LanguageType language_type) {
m_language = SourceLanguage(language_type);
}

/// Set the language using a pair of language code and version as
/// defined by the DWARF 6 specification.
/// WARNING: These codes may change until DWARF 6 is finalized.
void SetLanguage(uint16_t dwarf_lname_code, uint32_t dwarf_lversion) {
m_language = SourceLanguage(dwarf_lname_code, dwarf_lversion);
}

bool DoesCoerceToId() const { return m_coerce_to_id; }

Expand Down Expand Up @@ -445,7 +454,7 @@ class EvaluateExpressionOptions {

private:
ExecutionPolicy m_execution_policy = default_execution_policy;
lldb::LanguageType m_language = lldb::eLanguageTypeUnknown;
SourceLanguage m_language;
std::string m_prefix;
bool m_coerce_to_id = false;
bool m_unwind_on_error = true;
Expand Down Expand Up @@ -1160,7 +1169,7 @@ class Target : public std::enable_shared_from_this<Target>,

UserExpression *
GetUserExpressionForLanguage(llvm::StringRef expr, llvm::StringRef prefix,
lldb::LanguageType language,
SourceLanguage language,
Expression::ResultType desired_type,
const EvaluateExpressionOptions &options,
ValueObject *ctx_obj, Status &error);
Expand Down
19 changes: 19 additions & 0 deletions lldb/include/lldb/lldb-private-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,25 @@ struct RegisterSet {
const uint32_t *registers;
};

/// A type-erased pair of llvm::dwarf::SourceLanguageName and version.
struct SourceLanguage {
SourceLanguage() = default;
SourceLanguage(lldb::LanguageType language_type);
SourceLanguage(uint32_t name, uint16_t version)
: name(name), version(version) {}
SourceLanguage(std::optional<std::pair<uint32_t, uint16_t>> name_vers)
: name(name_vers ? name_vers->first : 0),
version(name_vers ? name_vers->second : 0) {}
operator bool() const { return name > 0; }
lldb::LanguageType AsLanguageType() const;
llvm::StringRef GetDescription() const;
bool IsC() const;
bool IsObjC() const;
bool IsCPlusPlus() const;
uint16_t name = 0;
uint32_t version = 0;
};

struct OptionEnumValueElement {
int64_t value;
const char *string_value;
Expand Down
1 change: 1 addition & 0 deletions lldb/packages/Python/lldbsuite/test/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@

# LLDB library directory.
lldb_libs_dir = None
lldb_built_include_dir = None

libcxx_include_dir = None
libcxx_include_target_dir = None
Expand Down
3 changes: 3 additions & 0 deletions lldb/packages/Python/lldbsuite/test/dotest.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ def parseOptionsAndInitTestdirs():
configuration.lldb_module_cache_dir = os.path.join(
configuration.test_build_dir, "module-cache-lldb"
)

if args.clang_module_cache_dir:
configuration.clang_module_cache_dir = args.clang_module_cache_dir
else:
Expand All @@ -432,6 +433,8 @@ def parseOptionsAndInitTestdirs():

if args.lldb_libs_dir:
configuration.lldb_libs_dir = args.lldb_libs_dir
if args.lldb_built_include_dir:
configuration.lldb_built_include_dir = args.lldb_built_include_dir

if args.enabled_plugins:
configuration.enabled_plugins = args.enabled_plugins
Expand Down
6 changes: 6 additions & 0 deletions lldb/packages/Python/lldbsuite/test/dotest_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,12 @@ def create_parser():
metavar="The clang module cache directory used by Clang",
help="The clang module cache directory used in the Make files by Clang while building tests. Defaults to <test build directory>/module-cache-clang.",
)
group.add_argument(
"--lldb-built-include-dir",
dest="lldb_built_include_dir",
metavar="path",
help="The path to LLDB built includes directory (containing languages.h)",
)
group.add_argument(
"--lldb-libs-dir",
dest="lldb_libs_dir",
Expand Down
6 changes: 4 additions & 2 deletions lldb/packages/Python/lldbsuite/test/lldbtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1473,23 +1473,25 @@ def buildDriver(self, sources, exe_name):
d = {
"CXX_SOURCES": sources,
"EXE": exe_name,
"CFLAGS_EXTRAS": "%s %s -I%s"
"CFLAGS_EXTRAS": "%s %s -I%s -I%s"
% (
stdflag,
stdlibflag,
os.path.join(os.environ["LLDB_SRC"], "include"),
os.path.join(os.environ["LLDB_FRAMEWORK"], "../include"),
),
"LD_EXTRAS": "-L%s -lliblldb" % lib_dir,
}
else:
d = {
"CXX_SOURCES": sources,
"EXE": exe_name,
"CFLAGS_EXTRAS": "%s %s -I%s"
"CFLAGS_EXTRAS": "%s %s -I%s -I%s"
% (
stdflag,
stdlibflag,
os.path.join(os.environ["LLDB_SRC"], "include"),
os.path.join(os.environ["LLDB_FRAMEWORK"], "../include"),
),
"LD_EXTRAS": "-L%s -llldb -Wl,-rpath,%s" % (lib_dir, lib_dir),
}
Expand Down
7 changes: 7 additions & 0 deletions lldb/source/API/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ if(LLDB_ENABLE_LUA)
set(lldb_lua_wrapper ${lua_bindings_dir}/LLDBWrapLua.cpp)
endif()

lldb_tablegen(../../include/lldb/API/Languages.h -gen-lldb-sbapi-dwarf-enum
SOURCE ${LLVM_MAIN_INCLUDE_DIR}/llvm/BinaryFormat/Dwarf.def
TARGET lldb-sbapi-dwarf-enums)

add_lldb_library(liblldb SHARED ${option_framework}
SBAddress.cpp
SBAttachInfo.cpp
Expand Down Expand Up @@ -100,6 +104,9 @@ add_lldb_library(liblldb SHARED ${option_framework}
${lldb_python_wrapper}
${lldb_lua_wrapper}

DEPENDS
lldb-sbapi-dwarf-enums

LINK_LIBS
lldbBreakpoint
lldbCore
Expand Down
7 changes: 7 additions & 0 deletions lldb/source/API/SBExpressionOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ void SBExpressionOptions::SetLanguage(lldb::LanguageType language) {
m_opaque_up->SetLanguage(language);
}

void SBExpressionOptions::SetLanguage(uint16_t dwarf_lname_code,
uint32_t dwarf_lversion) {
LLDB_INSTRUMENT_VA(this, dwarf_lname_code, dwarf_lversion);

m_opaque_up->SetLanguage(dwarf_lname_code, dwarf_lversion);
}

void SBExpressionOptions::SetCancelCallback(
lldb::ExpressionCancelCallback callback, void *baton) {
LLDB_INSTRUMENT_VA(this, callback, baton);
Expand Down
30 changes: 17 additions & 13 deletions lldb/source/API/SBFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1024,10 +1024,10 @@ SBValue SBFrame::EvaluateExpression(const char *expr) {
options.SetFetchDynamicValue(fetch_dynamic_value);
options.SetUnwindOnError(true);
options.SetIgnoreBreakpoints(true);
if (target->GetLanguage() != eLanguageTypeUnknown)
options.SetLanguage(target->GetLanguage());
else
options.SetLanguage(frame->GetLanguage());
SourceLanguage lang = target->GetLanguage();
if (!lang)
lang = frame->GetLanguage();
options.SetLanguage(lang.name, lang.version);
return EvaluateExpression(expr, options);
} else {
Status error;
Expand All @@ -1053,10 +1053,12 @@ SBFrame::EvaluateExpression(const char *expr,

StackFrame *frame = exe_ctx.GetFramePtr();
Target *target = exe_ctx.GetTargetPtr();
if (target && target->GetLanguage() != eLanguageTypeUnknown)
options.SetLanguage(target->GetLanguage());
else if (frame)
options.SetLanguage(frame->GetLanguage());
SourceLanguage language;
if (target)
language = target->GetLanguage();
if (!language && frame)
language = frame->GetLanguage();
options.SetLanguage(language.name, language.version);
return EvaluateExpression(expr, options);
}

Expand All @@ -1074,10 +1076,12 @@ SBValue SBFrame::EvaluateExpression(const char *expr,
options.SetIgnoreBreakpoints(true);
StackFrame *frame = exe_ctx.GetFramePtr();
Target *target = exe_ctx.GetTargetPtr();
if (target && target->GetLanguage() != eLanguageTypeUnknown)
options.SetLanguage(target->GetLanguage());
else if (frame)
options.SetLanguage(frame->GetLanguage());
SourceLanguage language;
if (target)
language = target->GetLanguage();
if (!language && frame)
language = frame->GetLanguage();
options.SetLanguage(language.name, language.version);
return EvaluateExpression(expr, options);
}

Expand Down Expand Up @@ -1218,7 +1222,7 @@ lldb::LanguageType SBFrame::GuessLanguage() const {
if (stop_locker.TryLock(&process->GetRunLock())) {
frame = exe_ctx.GetFramePtr();
if (frame) {
return frame->GuessLanguage();
return frame->GuessLanguage().AsLanguageType();
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions lldb/source/Breakpoint/Watchpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,9 +460,8 @@ void Watchpoint::SetCondition(const char *condition) {
// Pass nullptr for expr_prefix (no translation-unit level definitions).
Status error;
m_condition_up.reset(m_target.GetUserExpressionForLanguage(
condition, llvm::StringRef(), lldb::eLanguageTypeUnknown,
UserExpression::eResultTypeAny, EvaluateExpressionOptions(), nullptr,
error));
condition, {}, {}, UserExpression::eResultTypeAny,
EvaluateExpressionOptions(), nullptr, error));
if (error.Fail()) {
// FIXME: Log something...
m_condition_up.reset();
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Commands/CommandObjectDWIMPrint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
// Either Swift was explicitly specified, or the frame is Swift.
lldb::LanguageType language = m_expr_options.language;
if (language == lldb::eLanguageTypeUnknown && frame)
language = frame->GuessLanguage();
language = frame->GuessLanguage().AsLanguageType();

// Add a hint if object description was requested, but no description
// function was implemented.
Expand Down
Loading

0 comments on commit aba61b2

Please sign in to comment.