Index: include/lldb/Target/LanguageRuntime.h =================================================================== --- include/lldb/Target/LanguageRuntime.h +++ include/lldb/Target/LanguageRuntime.h @@ -22,6 +22,7 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Core/Value.h" #include "lldb/Target/ExecutionContextScope.h" +#include "clang/Basic/TargetOptions.h" namespace lldb_private { @@ -30,6 +31,7 @@ { public: + class OverrideExprOptions : public clang::TargetOptions {}; ~LanguageRuntime() override; static LanguageRuntime* @@ -150,6 +152,18 @@ { } + virtual OverrideExprOptions * + GetOverrideExprOptions() + { + return nullptr; + } + + virtual bool + SetOverrideExprOptions(OverrideExprOptions *opts) + { + return false; + } + protected: //------------------------------------------------------------------ // Classes that inherit from LanguageRuntime can see and modify these Index: source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp =================================================================== --- source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -76,11 +76,27 @@ #include "lldb/Target/ObjCLanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" +#include "lldb/Target/Language.h" using namespace clang; using namespace llvm; using namespace lldb_private; +namespace { + void debugStringVector(Log *log, const std::vector& vec, const char *name) + { + if(!log) + return; + + log->Debug("Begin %s:", name); + for (const auto& s : vec) + log->Debug("%s", s.c_str()); + + log->Debug("End %s.", name); + } +} + + //===----------------------------------------------------------------------===// // Utility Methods for Clang //===----------------------------------------------------------------------===// @@ -166,54 +182,121 @@ m_code_generator (), m_pp_callbacks(nullptr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + // 1. Create a new compiler instance. m_compiler.reset(new CompilerInstance()); - - // 2. Install the target. - + lldb::LanguageType frame_lang = lldb::eLanguageTypeUnknown; + lldb_private::LanguageRuntime::OverrideExprOptions *target_opts_override = nullptr; + lldb_private::LanguageRuntime *lang_rt = nullptr; lldb::TargetSP target_sp; if (exe_scope) target_sp = exe_scope->CalculateTarget(); - // TODO: figure out what to really do when we don't have a valid target. - // Sometimes this will be ok to just use the host target triple (when we - // evaluate say "2+3", but other expressions like breakpoint conditions - // and other things that _are_ target specific really shouldn't just be - // using the host triple. This needs to be fixed in a better way. - if (target_sp && target_sp->GetArchitecture().IsValid()) + // If the expression is being evaluated in the context of an existing + // stack frame, we introspect to see if the language runtime is available. + auto frame = exe_scope->CalculateStackFrame(); + if (frame) + frame_lang = frame->GetLanguage(); + + if (frame_lang != lldb::eLanguageTypeUnknown) { - std::string triple = target_sp->GetArchitecture().GetTriple().str(); - m_compiler->getTargetOpts().Triple = triple; + lang_rt = exe_scope->CalculateProcess()->GetLanguageRuntime(frame_lang); + if (log) + log->Printf("Frame has language of type %s", Language::GetNameForLanguageType(frame_lang)); } - else + + // 2. Configure the target, overriding with any custom options we can get. + if (lang_rt) { - m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple(); + // The expression is being evaluated in a known LanguageRuntime and StackFrame. + // We check if there are any overridden options for the evaluation, and configure + // the compiler appropriately. + target_opts_override = lang_rt->GetOverrideExprOptions(); } - if (target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86 || - target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86_64) + if (target_opts_override) { - m_compiler->getTargetOpts().Features.push_back("+sse"); - m_compiler->getTargetOpts().Features.push_back("+sse2"); + if (log) + log->Debug("Using overridden target options for the expression evaluation"); + + // If we get here this means the given language runtime has a custom set of code + // generation requirements, and they are configured from the language runtime. + m_compiler->getTargetOpts().Features = target_opts_override->Features; + m_compiler->getTargetOpts().CPU = target_opts_override->CPU; + m_compiler->getTargetOpts().Triple = target_opts_override->Triple; + m_compiler->getTargetOpts().FeaturesAsWritten = target_opts_override->FeaturesAsWritten; + m_compiler->getTargetOpts().Reciprocals = target_opts_override->Reciprocals; + } + else + { + // In this case, a specialized language runtime is not available and + // we have to fallback to making some basic assumptions on the target architecture. + // For 99% of use cases, this will be fine and is assumed to be the default. + if (target_sp && target_sp->GetArchitecture().IsValid()) + { + std::string triple = target_sp->GetArchitecture().GetTriple().str(); + m_compiler->getTargetOpts().Triple = triple; + if (log) + log->Printf("Using %s as the target triple", m_compiler->getTargetOpts().Triple.c_str()); + } + else + { + // If we get here we don't have a valid target and just have to guess. + // Sometimes this will be ok to just use the host target triple (when we + // evaluate say "2+3", but other expressions like breakpoint conditions + // and other things that _are_ target specific really shouldn't just be + // using the host triple. In such a case the language runtime should + // expose an overridden options set rather than letting this default path execute. + m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple(); + if (log) + log->Printf("Using default target triple of %s", m_compiler->getTargetOpts().Triple.c_str()); + } + // Now add some special fixes for known architectures: + // Any arm32 iOS environment, but not on arm64 + if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos && + m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos && + m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos) + { + m_compiler->getTargetOpts().ABI = "apcs-gnu"; + } + // Supported subsets of x86 + if (target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86 || + target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86_64) + { + m_compiler->getTargetOpts().Features.push_back("+sse"); + m_compiler->getTargetOpts().Features.push_back("+sse2"); + } } - // Any arm32 iOS environment, but not on arm64 - if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos && - m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos && - m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos) + if (log) { - m_compiler->getTargetOpts().ABI = "apcs-gnu"; + auto opts = m_compiler->getTargetOpts(); + log->Debug("Triple: '%s'", opts.Triple.c_str()); + log->Debug("CPU: '%s'", opts.CPU.c_str()); + log->Debug("FPMath: '%s'", opts.FPMath.c_str()); + log->Debug("ABI: '%s'", opts.ABI.c_str()); + log->Debug("LinkerVersion: '%s'", opts.LinkerVersion.c_str()); + debugStringVector(log, opts.FeaturesAsWritten, "FeaturesAsWritten"); + debugStringVector(log, opts.Features, "Features"); + debugStringVector(log, opts.Reciprocals, "Reciprocals"); } + // 3. Create and install the target on the compiler. m_compiler->createDiagnostics(); - - // Create the target instance. - m_compiler->setTarget(TargetInfo::CreateTargetInfo( - m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts)); + auto target_info = TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts); + if (log) + { + log->Printf("Using SIMD alignment: %d", target_info->getSimdDefaultAlign()); + log->Printf("Target datalayout string: '%s'", target_info->getDataLayoutString()); + log->Printf("Target ABI: '%s'", target_info->getABI().str().c_str()); + log->Printf("Target vector alignment: %d", target_info->getMaxVectorAlign()); + } + m_compiler->setTarget(target_info); assert (m_compiler->hasTarget()); - // 3. Set options. + // 4. Set language options. lldb::LanguageType language = expr.Language(); @@ -321,11 +404,11 @@ // created. This complexity should be lifted elsewhere. m_compiler->getTarget().adjust(m_compiler->getLangOpts()); - // 4. Set up the diagnostic buffer for reporting errors + // 5. Set up the diagnostic buffer for reporting errors m_compiler->getDiagnostics().setClient(new clang::TextDiagnosticBuffer); - // 5. Set up the source management objects inside the compiler + // 6. Set up the source management objects inside the compiler clang::FileSystemOptions file_system_options; m_file_manager.reset(new clang::FileManager(file_system_options)); @@ -344,7 +427,7 @@ m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks)); } - // 6. Most of this we get from the CompilerInstance, but we + // 7. Most of this we get from the CompilerInstance, but we // also want to give the context an ExternalASTSource. m_selector_table.reset(new SelectorTable()); m_builtin_context.reset(new Builtin::Context());