ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
                                              Expression &expr,
                                              bool generate_debug_info) :
    ExpressionParser (exe_scope, expr, generate_debug_info),
    m_compiler (),
    m_builtin_context (),
    m_selector_table (),
    m_code_generator (),
    m_pp_callbacks(nullptr)
{
    // 1. Create a new compiler instance.
    m_compiler.reset(new CompilerInstance());
    
    // Register the support for object-file-wrapped Clang modules.
    std::shared_ptr<clang::PCHContainerOperations> pch_operations = m_compiler->getPCHContainerOperations();
    pch_operations->registerWriter(llvm::make_unique<ObjectFilePCHContainerWriter>());
    pch_operations->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>());

    // 2. Install the target.

    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())
    {
        std::string triple = target_sp->GetArchitecture().GetTriple().str();
        m_compiler->getTargetOpts().Triple = triple;
    }
    else
    {
        m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
    }
    
    m_compiler->getTargetOpts().CPU = "";

    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)
    {
        m_compiler->getTargetOpts().ABI = "apcs-gnu";
    }

    m_compiler->createDiagnostics();

    // Create the target instance.
    m_compiler->setTarget(TargetInfo::CreateTargetInfo(
        m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts));

    assert (m_compiler->hasTarget());

    // 3. Set options.

    lldb::LanguageType language = expr.Language();

    switch (language)
    {
    case lldb::eLanguageTypeC:
    case lldb::eLanguageTypeC89:
    case lldb::eLanguageTypeC99:
    case lldb::eLanguageTypeC11:
        // FIXME: the following language option is a temporary workaround,
        // to "ask for C, get C++."
        // For now, the expression parser must use C++ anytime the
        // language is a C family language, because the expression parser
        // uses features of C++ to capture values.
        m_compiler->getLangOpts().CPlusPlus = true;
        break;
    case lldb::eLanguageTypeObjC:
        m_compiler->getLangOpts().ObjC1 = true;
        m_compiler->getLangOpts().ObjC2 = true;
        // FIXME: the following language option is a temporary workaround,
        // to "ask for ObjC, get ObjC++" (see comment above).
        m_compiler->getLangOpts().CPlusPlus = true;
        break;
    case lldb::eLanguageTypeC_plus_plus:
    case lldb::eLanguageTypeC_plus_plus_11:
    case lldb::eLanguageTypeC_plus_plus_14:
        m_compiler->getLangOpts().CPlusPlus11 = true;
        m_compiler->getHeaderSearchOpts().UseLibcxx = true;
        // fall thru ...
    case lldb::eLanguageTypeC_plus_plus_03:
        m_compiler->getLangOpts().CPlusPlus = true;
        // FIXME: the following language option is a temporary workaround,
        // to "ask for C++, get ObjC++".  Apple hopes to remove this requirement
        // on non-Apple platforms, but for now it is needed.
        m_compiler->getLangOpts().ObjC1 = true;
        break;
    case lldb::eLanguageTypeObjC_plus_plus:
    case lldb::eLanguageTypeUnknown:
    default:
        m_compiler->getLangOpts().ObjC1 = true;
        m_compiler->getLangOpts().ObjC2 = true;
        m_compiler->getLangOpts().CPlusPlus = true;
        m_compiler->getLangOpts().CPlusPlus11 = true;
        m_compiler->getHeaderSearchOpts().UseLibcxx = true;
        break;
    }

    m_compiler->getLangOpts().Bool = true;
    m_compiler->getLangOpts().WChar = true;
    m_compiler->getLangOpts().Blocks = true;
    m_compiler->getLangOpts().DebuggerSupport = true; // Features specifically for debugger clients
    if (expr.DesiredResultType() == Expression::eResultTypeId)
        m_compiler->getLangOpts().DebuggerCastResultToId = true;

    m_compiler->getLangOpts().CharIsSigned =
            ArchSpec(m_compiler->getTargetOpts().Triple.c_str()).CharIsSignedByDefault();

    // Spell checking is a nice feature, but it ends up completing a
    // lot of types that we didn't strictly speaking need to complete.
    // As a result, we spend a long time parsing and importing debug
    // information.
    m_compiler->getLangOpts().SpellChecking = false;

    lldb::ProcessSP process_sp;
    if (exe_scope)
        process_sp = exe_scope->CalculateProcess();

    if (process_sp && m_compiler->getLangOpts().ObjC1)
    {
        if (process_sp->GetObjCLanguageRuntime())
        {
            if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() == ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2)
                m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7));
            else
                m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::FragileMacOSX, VersionTuple(10, 7));

            if (process_sp->GetObjCLanguageRuntime()->HasNewLiteralsAndIndexing())
                m_compiler->getLangOpts().DebuggerObjCLiteral = true;
        }
    }

    m_compiler->getLangOpts().ThreadsafeStatics = false;
    m_compiler->getLangOpts().AccessControl = false; // Debuggers get universal access
    m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name

    // Set CodeGen options
    m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
    m_compiler->getCodeGenOpts().InstrumentFunctions = false;
    m_compiler->getCodeGenOpts().DisableFPElim = true;
    m_compiler->getCodeGenOpts().OmitLeafFramePointer = false;
    if (generate_debug_info)
        m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::FullDebugInfo);
    else
        m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::NoDebugInfo);

    // Disable some warnings.
    m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError,
        "unused-value", clang::diag::Severity::Ignored, SourceLocation());
    m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError,
        "odr", clang::diag::Severity::Ignored, SourceLocation());

    // Inform the target of the language options
    //
    // FIXME: We shouldn't need to do this, the target should be immutable once
    // created. This complexity should be lifted elsewhere.
    m_compiler->getTarget().adjust(m_compiler->getLangOpts());

    // 4. 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

    clang::FileSystemOptions file_system_options;
    m_file_manager.reset(new clang::FileManager(file_system_options));

    if (!m_compiler->hasSourceManager())
        m_compiler->createSourceManager(*m_file_manager.get());

    m_compiler->createFileManager();
    m_compiler->createPreprocessor(TU_Complete);
    
    if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor())
    {
        ClangPersistentVariables *clang_persistent_vars = llvm::cast<ClangPersistentVariables>(target_sp->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));
        std::unique_ptr<PPCallbacks> pp_callbacks(new LLDBPreprocessorCallbacks(*decl_vendor, *clang_persistent_vars));
        m_pp_callbacks = static_cast<LLDBPreprocessorCallbacks*>(pp_callbacks.get());
        m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks));
    }
        
    // 6. 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());

    std::unique_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(),
                                                                  m_compiler->getSourceManager(),
                                                                  m_compiler->getPreprocessor().getIdentifierTable(),
                                                                  *m_selector_table.get(),
                                                                  *m_builtin_context.get()));
    
    ast_context->InitBuiltinTypes(m_compiler->getTarget());

    ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
    ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap();

    if (decl_map)
    {
        llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source(decl_map->CreateProxy());
        decl_map->InstallASTContext(ast_context.get());
        ast_context->setExternalSource(ast_source);
    }

    m_ast_context.reset(new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str()));
    m_ast_context->setASTContext(ast_context.get());
    m_compiler->setASTContext(ast_context.release());

    std::string module_name("$__lldb_module");

    m_llvm_context.reset(new LLVMContext());

    m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(),
                                             module_name,
                                             m_compiler->getHeaderSearchOpts(),
                                             m_compiler->getPreprocessorOpts(),
                                             m_compiler->getCodeGenOpts(),
                                             *m_llvm_context));
}
Пример #2
0
ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
                                              Expression &expr,
                                              bool generate_debug_info) :
    ExpressionParser (exe_scope, expr, generate_debug_info),
    m_compiler (),
    m_code_generator (),
    m_pp_callbacks(nullptr)
{
    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));

    // We can't compile expressions without a target.  So if the exe_scope is null or doesn't have a target,
    // then we just need to get out of here.  I'll lldb_assert and not make any of the compiler objects since
    // I can't return errors directly from the constructor.  Further calls will check if the compiler was made and
    // bag out if it wasn't.
    
    if (!exe_scope)
    {
        lldb_assert(exe_scope, "Can't make an expression parser with a null scope.", __FUNCTION__, __FILE__, __LINE__);
        return;
    }
    
    lldb::TargetSP target_sp;
    target_sp = exe_scope->CalculateTarget();
    if (!target_sp)
    {
        lldb_assert(exe_scope, "Can't make an expression parser with a null target.", __FUNCTION__, __FILE__, __LINE__);
        return;
    }
    
    // 1. Create a new compiler instance.
    m_compiler.reset(new CompilerInstance());
    lldb::LanguageType frame_lang = expr.Language(); // defaults to lldb::eLanguageTypeUnknown
    bool overridden_target_opts = false;
    lldb_private::LanguageRuntime *lang_rt = nullptr;

    std::string abi;
    ArchSpec target_arch;
    target_arch = target_sp->GetArchitecture();

    const auto target_machine = target_arch.GetMachine();

    // If the expression is being evaluated in the context of an existing
    // stack frame, we introspect to see if the language runtime is available.
    
    lldb::StackFrameSP frame_sp = exe_scope->CalculateStackFrame();
    lldb::ProcessSP process_sp = exe_scope->CalculateProcess();
    
    // Make sure the user hasn't provided a preferred execution language
    // with `expression --language X -- ...`
    if (frame_sp && frame_lang == lldb::eLanguageTypeUnknown)
        frame_lang = frame_sp->GetLanguage();

    if (process_sp && frame_lang != lldb::eLanguageTypeUnknown)
    {
        lang_rt = process_sp->GetLanguageRuntime(frame_lang);
        if (log)
            log->Printf("Frame has language of type %s", Language::GetNameForLanguageType(frame_lang));
    }

    // 2. Configure the compiler with a set of default options that are appropriate
    // for most situations.
    if (target_arch.IsValid())
    {
        std::string triple = target_arch.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 (3),
        // below.
        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_machine == llvm::Triple::x86 ||
        target_machine == llvm::Triple::x86_64)
    {
        m_compiler->getTargetOpts().Features.push_back("+sse");
        m_compiler->getTargetOpts().Features.push_back("+sse2");
    }

    // Set the target CPU to generate code for.
    // This will be empty for any CPU that doesn't really need to make a special CPU string.
    m_compiler->getTargetOpts().CPU = target_arch.GetClangTargetCPU();

    // Set the target ABI
    abi = GetClangTargetABI(target_arch);
    if (!abi.empty())
        m_compiler->getTargetOpts().ABI = abi;

    // 3. Now allow the runtime to provide custom configuration options for the target.
    // In this case, a specialized language runtime is available and we can query it for extra options.
    // For 99% of use cases, this will not be needed and should be provided when basic platform detection is not enough.
    if (lang_rt)
        overridden_target_opts = lang_rt->GetOverrideExprOptions(m_compiler->getTargetOpts());

    if (overridden_target_opts)
        if (log)
        {
            log->Debug("Using overridden target options for the expression evaluation");

            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());
            StringList::LogDump(log, opts.FeaturesAsWritten, "FeaturesAsWritten");
            StringList::LogDump(log, opts.Features, "Features");
            StringList::LogDump(log, opts.Reciprocals, "Reciprocals");
        }

    // 4. Create and install the target on the compiler.
    m_compiler->createDiagnostics();
    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->getDataLayout().getStringRepresentation().c_str());
        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());

    // 5. Set language options.
    lldb::LanguageType language = expr.Language();

    switch (language)
    {
    case lldb::eLanguageTypeC:
    case lldb::eLanguageTypeC89:
    case lldb::eLanguageTypeC99:
    case lldb::eLanguageTypeC11:
        // FIXME: the following language option is a temporary workaround,
        // to "ask for C, get C++."
        // For now, the expression parser must use C++ anytime the
        // language is a C family language, because the expression parser
        // uses features of C++ to capture values.
        m_compiler->getLangOpts().CPlusPlus = true;
        break;
    case lldb::eLanguageTypeObjC:
        m_compiler->getLangOpts().ObjC1 = true;
        m_compiler->getLangOpts().ObjC2 = true;
        // FIXME: the following language option is a temporary workaround,
        // to "ask for ObjC, get ObjC++" (see comment above).
        m_compiler->getLangOpts().CPlusPlus = true;
        break;
    case lldb::eLanguageTypeC_plus_plus:
    case lldb::eLanguageTypeC_plus_plus_11:
    case lldb::eLanguageTypeC_plus_plus_14:
        m_compiler->getLangOpts().CPlusPlus11 = true;
        m_compiler->getHeaderSearchOpts().UseLibcxx = true;
        LLVM_FALLTHROUGH;
    case lldb::eLanguageTypeC_plus_plus_03:
        m_compiler->getLangOpts().CPlusPlus = true;
        // FIXME: the following language option is a temporary workaround,
        // to "ask for C++, get ObjC++".  Apple hopes to remove this requirement
        // on non-Apple platforms, but for now it is needed.
        m_compiler->getLangOpts().ObjC1 = true;
        break;
    case lldb::eLanguageTypeObjC_plus_plus:
    case lldb::eLanguageTypeUnknown:
    default:
        m_compiler->getLangOpts().ObjC1 = true;
        m_compiler->getLangOpts().ObjC2 = true;
        m_compiler->getLangOpts().CPlusPlus = true;
        m_compiler->getLangOpts().CPlusPlus11 = true;
        m_compiler->getHeaderSearchOpts().UseLibcxx = true;
        break;
    }

    m_compiler->getLangOpts().Bool = true;
    m_compiler->getLangOpts().WChar = true;
    m_compiler->getLangOpts().Blocks = true;
    m_compiler->getLangOpts().DebuggerSupport = true; // Features specifically for debugger clients
    if (expr.DesiredResultType() == Expression::eResultTypeId)
        m_compiler->getLangOpts().DebuggerCastResultToId = true;

    m_compiler->getLangOpts().CharIsSigned =
            ArchSpec(m_compiler->getTargetOpts().Triple.c_str()).CharIsSignedByDefault();

    // Spell checking is a nice feature, but it ends up completing a
    // lot of types that we didn't strictly speaking need to complete.
    // As a result, we spend a long time parsing and importing debug
    // information.
    m_compiler->getLangOpts().SpellChecking = false;

    if (process_sp && m_compiler->getLangOpts().ObjC1)
    {
        if (process_sp->GetObjCLanguageRuntime())
        {
            if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() == ObjCLanguageRuntime::ObjCRuntimeVersions::eAppleObjC_V2)
                m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7));
            else
                m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::FragileMacOSX, VersionTuple(10, 7));

            if (process_sp->GetObjCLanguageRuntime()->HasNewLiteralsAndIndexing())
                m_compiler->getLangOpts().DebuggerObjCLiteral = true;
        }
    }

    m_compiler->getLangOpts().ThreadsafeStatics = false;
    m_compiler->getLangOpts().AccessControl = false; // Debuggers get universal access
    m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name

    // Set CodeGen options
    m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
    m_compiler->getCodeGenOpts().InstrumentFunctions = false;
    m_compiler->getCodeGenOpts().DisableFPElim = true;
    m_compiler->getCodeGenOpts().OmitLeafFramePointer = false;
    if (generate_debug_info)
        m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);
    else
        m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::NoDebugInfo);

    // Disable some warnings.
    m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError,
        "unused-value", clang::diag::Severity::Ignored, SourceLocation());
    m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError,
        "odr", clang::diag::Severity::Ignored, SourceLocation());

    // Inform the target of the language options
    //
    // FIXME: We shouldn't need to do this, the target should be immutable once
    // created. This complexity should be lifted elsewhere.
    m_compiler->getTarget().adjust(m_compiler->getLangOpts());

    // 6. Set up the diagnostic buffer for reporting errors

    m_compiler->getDiagnostics().setClient(new ClangDiagnosticManagerAdapter);

    // 7. Set up the source management objects inside the compiler

    clang::FileSystemOptions file_system_options;
    m_file_manager.reset(new clang::FileManager(file_system_options));

    if (!m_compiler->hasSourceManager())
        m_compiler->createSourceManager(*m_file_manager.get());

    m_compiler->createFileManager();
    m_compiler->createPreprocessor(TU_Complete);
    
    if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor())
    {
        ClangPersistentVariables *clang_persistent_vars = llvm::cast<ClangPersistentVariables>(target_sp->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));
        std::unique_ptr<PPCallbacks> pp_callbacks(new LLDBPreprocessorCallbacks(*decl_vendor, *clang_persistent_vars));
        m_pp_callbacks = static_cast<LLDBPreprocessorCallbacks*>(pp_callbacks.get());
        m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks));
    }
        
    // 8. 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());

    std::unique_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(),
                                                                  m_compiler->getSourceManager(),
                                                                  m_compiler->getPreprocessor().getIdentifierTable(),
                                                                  *m_selector_table.get(),
                                                                  *m_builtin_context.get()));
    
    ast_context->InitBuiltinTypes(m_compiler->getTarget());

    ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
    ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap();

    if (decl_map)
    {
        llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source(decl_map->CreateProxy());
        decl_map->InstallASTContext(ast_context.get());
        ast_context->setExternalSource(ast_source);
    }

    m_ast_context.reset(new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str()));
    m_ast_context->setASTContext(ast_context.get());
    m_compiler->setASTContext(ast_context.release());

    std::string module_name("$__lldb_module");

    m_llvm_context.reset(new LLVMContext());
    m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(),
                                             module_name,
                                             m_compiler->getHeaderSearchOpts(),
                                             m_compiler->getPreprocessorOpts(),
                                             m_compiler->getCodeGenOpts(),
                                             *m_llvm_context));
}