diff options
Diffstat (limited to 'lldb/source')
-rw-r--r-- | lldb/source/Commands/CommandObjectCall.cpp | 11 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectExpression.cpp | 186 | ||||
-rw-r--r-- | lldb/source/Expression/ASTResultSynthesizer.cpp (renamed from lldb/source/Expression/ClangResultSynthesizer.cpp) | 30 | ||||
-rw-r--r-- | lldb/source/Expression/ASTStructExtractor.cpp | 191 | ||||
-rw-r--r-- | lldb/source/Expression/ClangExpression.cpp | 748 | ||||
-rw-r--r-- | lldb/source/Expression/ClangExpressionParser.cpp | 640 | ||||
-rw-r--r-- | lldb/source/Expression/ClangFunction.cpp | 363 | ||||
-rw-r--r-- | lldb/source/Expression/ClangUserExpression.cpp | 257 | ||||
-rw-r--r-- | lldb/source/Expression/IRForTarget.cpp | 10 | ||||
-rw-r--r-- | lldb/source/Expression/IRToDWARF.cpp | 16 | ||||
-rw-r--r-- | lldb/source/Interpreter/CommandInterpreter.cpp | 4 |
11 files changed, 1260 insertions, 1196 deletions
diff --git a/lldb/source/Commands/CommandObjectCall.cpp b/lldb/source/Commands/CommandObjectCall.cpp index b3dfc533b16..fe0ee534437 100644 --- a/lldb/source/Commands/CommandObjectCall.cpp +++ b/lldb/source/Commands/CommandObjectCall.cpp @@ -263,15 +263,8 @@ CommandObjectCall::Execute ClangFunction::ExecutionResults return_status; Value return_value; - if (m_options.use_abi) - { - return_status = clang_fun.ExecuteFunctionWithABI(exe_ctx, errors, return_value); - } - else - { - bool stop_others = true; - return_status = clang_fun.ExecuteFunction(exe_ctx, errors, stop_others, NULL, return_value); - } + bool stop_others = true; + return_status = clang_fun.ExecuteFunction(exe_ctx, errors, stop_others, NULL, return_value); // Now figure out what to do with the return value. if (return_status == ClangFunction::eExecutionSetupError) diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index af1041002b6..b29c0c7777d 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -16,10 +16,8 @@ #include "lldb/Interpreter/Args.h" #include "lldb/Core/Value.h" #include "lldb/Core/InputReader.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangExpressionDeclMap.h" #include "lldb/Expression/ClangExpressionVariable.h" -#include "lldb/Expression/ClangPersistentVariables.h" +#include "lldb/Expression/ClangUserExpression.h" #include "lldb/Expression/ClangFunction.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Host/Host.h" @@ -192,192 +190,22 @@ bool CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream, CommandReturnObject *result) { - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - //////////////////////////////////// - // Set up the target and compiler - // - - Target *target = m_exe_ctx.target; - - if (!target) - { - error_stream.PutCString ("error: invalid target\n"); - return false; - } + ClangUserExpression user_expression (expr); - ConstString target_triple; - - target->GetTargetTriple (target_triple); - - if (!target_triple) - target_triple = Host::GetTargetTriple (); - - if (!target_triple) + if (!user_expression.Parse (error_stream, m_exe_ctx)) { - error_stream.PutCString ("error: invalid target triple\n"); + error_stream.Printf ("Couldn't parse the expresssion"); return false; } - ClangExpressionDeclMap expr_decl_map (&m_exe_ctx); - ClangExpression clang_expr (target_triple.AsCString (), &expr_decl_map); - - ////////////////////////// - // Parse the expression - // - - unsigned num_errors; - - if (bare) - num_errors = clang_expr.ParseBareExpression (llvm::StringRef (expr), error_stream); - else - num_errors = clang_expr.ParseExpression (expr, error_stream, true); - - if (num_errors) - { - error_stream.Printf ("error: %d errors parsing expression\n", num_errors); - return false; - } - - /////////////////////////////////////////////// - // Convert the output of the parser to DWARF - // - - StreamString dwarf_opcodes; - dwarf_opcodes.SetByteOrder (eByteOrderHost); - dwarf_opcodes.GetFlags ().Set (Stream::eBinary); - - ClangExpressionVariableList expr_local_vars; - - bool success; - bool canInterpret = false; - - ClangExpressionVariable *expr_result = 0; - Error expr_error; - - canInterpret = clang_expr.ConvertIRToDWARF (expr_local_vars, dwarf_opcodes); - - if (canInterpret) - { - if (log) - log->Printf("Code can be interpreted."); - success = true; - } - else - { - if (log) - log->Printf("Code cannot be interpreted and must be run in the target."); - success = clang_expr.PrepareIRForTarget (); - } - - if (!success) - { - error_stream.PutCString ("error: expression couldn't be converted to IR\n"); - return false; - } + ClangExpressionVariable *expr_result; - if (canInterpret) + if (!user_expression.Execute (error_stream, m_exe_ctx, expr_result)) { - // TODO interpret IR + error_stream.Printf ("Couldn't execute the expresssion"); return false; } - else - { - if (!clang_expr.JITFunction ()) - { - error_stream.PutCString ("error: IR could not be JIT compiled\n"); - return false; - } - if (!clang_expr.WriteJITCode (m_exe_ctx)) - { - error_stream.PutCString ("error: JIT code could not be written to the target\n"); - return false; - } - - lldb::addr_t function_address(clang_expr.GetFunctionAddress ()); - - if (function_address == LLDB_INVALID_ADDRESS) - { - error_stream.PutCString ("JIT compiled code's address couldn't be found\n"); - return false; - } - - lldb::addr_t struct_address; - - if (!expr_decl_map.Materialize(&m_exe_ctx, struct_address, expr_error)) - { - error_stream.Printf ("Couldn't materialize struct: %s\n", expr_error.AsCString("unknown error")); - return false; - } - - if (log) - { - log->Printf("Function address : 0x%llx", (uint64_t)function_address); - log->Printf("Structure address : 0x%llx", (uint64_t)struct_address); - - StreamString insns; - - Error err = clang_expr.DisassembleFunction(insns, m_exe_ctx); - - if (!err.Success()) - { - log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); - } - else - { - log->Printf("Function disassembly:\n%s", insns.GetData()); - } - - StreamString args; - - if (!expr_decl_map.DumpMaterializedStruct(&m_exe_ctx, args, err)) - { - log->Printf("Couldn't extract variable values : %s", err.AsCString("unknown error")); - } - else - { - log->Printf("Structure contents:\n%s", args.GetData()); - } - } - - ClangFunction::ExecutionResults execution_result = - ClangFunction::ExecuteFunction (m_exe_ctx, function_address, struct_address, true, true, 10000, error_stream); - - if (execution_result != ClangFunction::eExecutionCompleted) - { - const char *result_name; - - switch (execution_result) - { - case ClangFunction::eExecutionCompleted: - result_name = "eExecutionCompleted"; - break; - case ClangFunction::eExecutionDiscarded: - result_name = "eExecutionDiscarded"; - break; - case ClangFunction::eExecutionInterrupted: - result_name = "eExecutionInterrupted"; - break; - case ClangFunction::eExecutionSetupError: - result_name = "eExecutionSetupError"; - break; - case ClangFunction::eExecutionTimedOut: - result_name = "eExecutionTimedOut"; - break; - } - - error_stream.Printf ("Couldn't execute function; result was %s\n", result_name); - return false; - } - - if (!expr_decl_map.Dematerialize(&m_exe_ctx, expr_result, expr_error)) - { - error_stream.Printf ("Couldn't dematerialize struct : %s\n", expr_error.AsCString("unknown error")); - return false; - } - } - if (expr_result) { StreamString ss; diff --git a/lldb/source/Expression/ClangResultSynthesizer.cpp b/lldb/source/Expression/ASTResultSynthesizer.cpp index b3922ee5ce4..b3790f2cae5 100644 --- a/lldb/source/Expression/ClangResultSynthesizer.cpp +++ b/lldb/source/Expression/ASTResultSynthesizer.cpp @@ -1,4 +1,4 @@ -//===-- ClangResultSynthesizer.cpp ------------------------------*- C++ -*-===// +//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -20,13 +20,13 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" #include "lldb/Core/Log.h" -#include "lldb/Expression/ClangResultSynthesizer.h" +#include "lldb/Expression/ASTResultSynthesizer.h" using namespace llvm; using namespace clang; using namespace lldb_private; -ClangResultSynthesizer::ClangResultSynthesizer(ASTConsumer *passthrough) : +ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough) : m_ast_context (NULL), m_passthrough (passthrough), m_passthrough_sema (NULL), @@ -39,12 +39,12 @@ ClangResultSynthesizer::ClangResultSynthesizer(ASTConsumer *passthrough) : m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough); } -ClangResultSynthesizer::~ClangResultSynthesizer() +ASTResultSynthesizer::~ASTResultSynthesizer() { } void -ClangResultSynthesizer::Initialize(ASTContext &Context) +ASTResultSynthesizer::Initialize(ASTContext &Context) { m_ast_context = &Context; @@ -53,7 +53,7 @@ ClangResultSynthesizer::Initialize(ASTContext &Context) } void -ClangResultSynthesizer::TransformTopLevelDecl(Decl* D) +ASTResultSynthesizer::TransformTopLevelDecl(Decl* D) { LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D); @@ -81,7 +81,7 @@ ClangResultSynthesizer::TransformTopLevelDecl(Decl* D) } void -ClangResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D) +ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D) { DeclGroupRef::iterator decl_iterator; @@ -99,7 +99,7 @@ ClangResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D) } bool -ClangResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl) +ASTResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl) { ASTContext &Ctx(*m_ast_context); @@ -210,42 +210,42 @@ ClangResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl) } void -ClangResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx) +ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx) { if (m_passthrough) m_passthrough->HandleTranslationUnit(Ctx); } void -ClangResultSynthesizer::HandleTagDeclDefinition(TagDecl *D) +ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D) { if (m_passthrough) m_passthrough->HandleTagDeclDefinition(D); } void -ClangResultSynthesizer::CompleteTentativeDefinition(VarDecl *D) +ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D) { if (m_passthrough) m_passthrough->CompleteTentativeDefinition(D); } void -ClangResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) +ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) { if (m_passthrough) m_passthrough->HandleVTable(RD, DefinitionRequired); } void -ClangResultSynthesizer::PrintStats() +ASTResultSynthesizer::PrintStats() { if (m_passthrough) m_passthrough->PrintStats(); } void -ClangResultSynthesizer::InitializeSema(Sema &S) +ASTResultSynthesizer::InitializeSema(Sema &S) { m_sema = &S; m_action = reinterpret_cast<Action*>(m_sema); @@ -255,7 +255,7 @@ ClangResultSynthesizer::InitializeSema(Sema &S) } void -ClangResultSynthesizer::ForgetSema() +ASTResultSynthesizer::ForgetSema() { m_sema = NULL; m_action = NULL; diff --git a/lldb/source/Expression/ASTStructExtractor.cpp b/lldb/source/Expression/ASTStructExtractor.cpp new file mode 100644 index 00000000000..84a97c8e5df --- /dev/null +++ b/lldb/source/Expression/ASTStructExtractor.cpp @@ -0,0 +1,191 @@ +//===-- ASTStructExtractor.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "stdlib.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclGroup.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Stmt.h" +#include "clang/Parse/Action.h" +#include "clang/Parse/Parser.h" +#include "clang/Parse/Scope.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" +#include "lldb/Core/Log.h" +#include "lldb/Expression/ASTStructExtractor.h" + +using namespace llvm; +using namespace clang; +using namespace lldb_private; + +ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough, + const char *struct_name, + ClangFunction &function) : + m_ast_context (NULL), + m_passthrough (passthrough), + m_passthrough_sema (NULL), + m_sema (NULL), + m_action (NULL), + m_struct_name (struct_name), + m_function (function) +{ + if (!m_passthrough) + return; + + m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough); +} + +ASTStructExtractor::~ASTStructExtractor() +{ +} + +void +ASTStructExtractor::Initialize(ASTContext &Context) +{ + m_ast_context = &Context; + + if (m_passthrough) + m_passthrough->Initialize(Context); +} + +void +ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F) +{ + DeclarationName struct_name(&m_ast_context->Idents.get(m_struct_name.c_str())); + RecordDecl::lookup_result struct_lookup = F->lookup(struct_name); + + if (struct_lookup.first == struct_lookup.second) + return; + + RecordDecl *struct_decl = dyn_cast<RecordDecl>(*(struct_lookup.first)); + + if (!struct_decl) + return; + + const ASTRecordLayout* struct_layout(&m_ast_context->getASTRecordLayout (struct_decl)); + + if (!struct_layout) + return; + + m_function.m_struct_size = struct_layout->getSize() / 8; // Clang returns sizes in bits. + m_function.m_return_offset = struct_layout->getFieldOffset(struct_layout->getFieldCount() - 1) / 8; + m_function.m_return_size = (struct_layout->getDataSize() / 8) - m_function.m_return_offset; + + for (unsigned field_index = 0, num_fields = struct_layout->getFieldCount(); + field_index < num_fields; + ++field_index) + { + m_function.m_member_offsets.push_back(struct_layout->getFieldOffset(field_index) / 8); + } + + m_function.m_struct_valid = true; +} + +void +ASTStructExtractor::ExtractFromTopLevelDecl(Decl* D) +{ + LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D); + + if (linkage_spec_decl) + { + RecordDecl::decl_iterator decl_iterator; + + for (decl_iterator = linkage_spec_decl->decls_begin(); + decl_iterator != linkage_spec_decl->decls_end(); + ++decl_iterator) + { + ExtractFromTopLevelDecl(*decl_iterator); + } + } + + FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D); + + if (m_ast_context && + function_decl && + !m_function.m_wrapper_function_name.compare(function_decl->getNameAsCString())) + { + ExtractFromFunctionDecl(function_decl); + } +} + +void +ASTStructExtractor::HandleTopLevelDecl(DeclGroupRef D) +{ + DeclGroupRef::iterator decl_iterator; + + for (decl_iterator = D.begin(); + decl_iterator != D.end(); + ++decl_iterator) + { + Decl *decl = *decl_iterator; + + ExtractFromTopLevelDecl(decl); + } + + if (m_passthrough) + m_passthrough->HandleTopLevelDecl(D); +} + +void +ASTStructExtractor::HandleTranslationUnit(ASTContext &Ctx) +{ + if (m_passthrough) + m_passthrough->HandleTranslationUnit(Ctx); +} + +void +ASTStructExtractor::HandleTagDeclDefinition(TagDecl *D) +{ + if (m_passthrough) + m_passthrough->HandleTagDeclDefinition(D); +} + +void +ASTStructExtractor::CompleteTentativeDefinition(VarDecl *D) +{ + if (m_passthrough) + m_passthrough->CompleteTentativeDefinition(D); +} + +void +ASTStructExtractor::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) +{ + if (m_passthrough) + m_passthrough->HandleVTable(RD, DefinitionRequired); +} + +void +ASTStructExtractor::PrintStats() +{ + if (m_passthrough) + m_passthrough->PrintStats(); +} + +void +ASTStructExtractor::InitializeSema(Sema &S) +{ + m_sema = &S; + m_action = reinterpret_cast<Action*>(m_sema); + + if (m_passthrough_sema) + m_passthrough_sema->InitializeSema(S); +} + +void +ASTStructExtractor::ForgetSema() +{ + m_sema = NULL; + m_action = NULL; + + if (m_passthrough_sema) + m_passthrough_sema->ForgetSema(); +} diff --git a/lldb/source/Expression/ClangExpression.cpp b/lldb/source/Expression/ClangExpression.cpp deleted file mode 100644 index 416bd3e3733..00000000000 --- a/lldb/source/Expression/ClangExpression.cpp +++ /dev/null @@ -1,748 +0,0 @@ -//===-- ClangExpression.cpp -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// C Includes -#include <stdio.h> -#if HAVE_SYS_TYPES_H -# include <sys/types.h> -#endif - -// C++ Includes -#include <cstdlib> -#include <string> -#include <map> - -// Other libraries and framework includes -#include "clang/AST/ASTContext.h" -#include "clang/AST/ExternalASTSource.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Version.h" -#include "clang/Checker/FrontendActions.h" -#include "clang/CodeGen/CodeGenAction.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/Driver/CC1Options.h" -#include "clang/Driver/OptTable.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/CompilerInvocation.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Frontend/FrontendPluginRegistry.h" -#include "clang/Frontend/TextDiagnosticBuffer.h" -#include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Frontend/VerifyDiagnosticsClient.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Rewrite/FrontendActions.h" -#include "clang/Sema/ParseAST.h" -#include "clang/Sema/SemaConsumer.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/JIT.h" -#include "llvm/Module.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/LLVMContext.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/System/DynamicLibrary.h" -#include "llvm/System/Host.h" -#include "llvm/System/Signals.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Target/TargetSelect.h" - -// Project includes -#include "lldb/Core/Log.h" -#include "lldb/Core/ClangForward.h" -#include "lldb/Core/DataBufferHeap.h" -#include "lldb/Core/Disassembler.h" -#include "lldb/Expression/ClangExpression.h" -#include "lldb/Expression/ClangASTSource.h" -#include "lldb/Expression/ClangResultSynthesizer.h" -#include "lldb/Expression/IRForTarget.h" -#include "lldb/Expression/IRToDWARF.h" -#include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Expression/RecordingMemoryManager.h" -#include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/Target.h" - -#include "lldb/Core/StreamString.h" -#include "lldb/Host/Mutex.h" - - -using namespace lldb_private; -using namespace clang; -using namespace llvm; - - -//===----------------------------------------------------------------------===// -// Utility Methods -//===----------------------------------------------------------------------===// - -std::string GetBuiltinIncludePath(const char *Argv0) { - llvm::sys::Path P = - llvm::sys::Path::GetMainExecutable(Argv0, - (void*)(intptr_t) GetBuiltinIncludePath); - - if (!P.isEmpty()) { - P.eraseComponent(); // Remove /clang from foo/bin/clang - P.eraseComponent(); // Remove /bin from foo/bin - - // Get foo/lib/clang/<version>/include - P.appendComponent("lib"); - P.appendComponent("clang"); - P.appendComponent(CLANG_VERSION_STRING); - P.appendComponent("include"); - } - - return P.str(); -} - - -//===----------------------------------------------------------------------===// -// Main driver -//===----------------------------------------------------------------------===// - -static void LLVMErrorHandler(void *UserData, const std::string &Message) { - Diagnostic &Diags = *static_cast<Diagnostic*>(UserData); - - Diags.Report(diag::err_fe_error_backend) << Message; - - // We cannot recover from llvm errors. - exit(1); -} - -static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { - using namespace clang::frontend; - - switch (CI.getFrontendOpts().ProgramAction) { - default: - llvm_unreachable("Invalid program action!"); - - case ASTDump: return new ASTDumpAction(); - case ASTPrint: return new ASTPrintAction(); - case ASTPrintXML: return new ASTPrintXMLAction(); - case ASTView: return new ASTViewAction(); - case BoostCon: return new BoostConAction(); - case DumpRawTokens: return new DumpRawTokensAction(); - case DumpTokens: return new DumpTokensAction(); - case EmitAssembly: return new EmitAssemblyAction(); - case EmitBC: return new EmitBCAction(); - case EmitHTML: return new HTMLPrintAction(); - case EmitLLVM: return new EmitLLVMAction(); - case EmitLLVMOnly: return new EmitLLVMOnlyAction(); - case EmitCodeGenOnly: return new EmitCodeGenOnlyAction(); - case EmitObj: return new EmitObjAction(); - case FixIt: return new FixItAction(); - case GeneratePCH: return new GeneratePCHAction(); - case GeneratePTH: return new GeneratePTHAction(); - case InheritanceView: return new InheritanceViewAction(); - case InitOnly: return new InitOnlyAction(); - case ParseSyntaxOnly: return new SyntaxOnlyAction(); - - case PluginAction: { - for (FrontendPluginRegistry::iterator it = - FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); - it != ie; ++it) { - if (it->getName() == CI.getFrontendOpts().ActionName) { - llvm::OwningPtr<PluginASTAction> P(it->instantiate()); - if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs)) - return 0; - return P.take(); - } - } - - CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) - << CI.getFrontendOpts().ActionName; - return 0; - } - - case PrintDeclContext: return new DeclContextPrintAction(); - case PrintPreamble: return new PrintPreambleAction(); - case PrintPreprocessedInput: return new PrintPreprocessedAction(); - case RewriteMacros: return new RewriteMacrosAction(); - case RewriteObjC: return new RewriteObjCAction(); - case RewriteTest: return new RewriteTestAction(); - case RunAnalysis: return new AnalysisAction(); - case RunPreprocessorOnly: return new PreprocessOnlyAction(); - } -} - -static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { - // Create the underlying action. - FrontendAction *Act = CreateFrontendBaseAction(CI); - if (!Act) - return 0; - - // If there are any AST files to merge, create a frontend action - // adaptor to perform the merge. - if (!CI.getFrontendOpts().ASTMergeFiles.empty()) - Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0], - CI.getFrontendOpts().ASTMergeFiles.size()); - - return Act; -} - -//---------------------------------------------------------------------- -// ClangExpression constructor -//---------------------------------------------------------------------- -ClangExpression::ClangExpression(const char *target_triple, - ClangExpressionDeclMap *decl_map) : - m_target_triple (), - m_decl_map (decl_map), - m_clang_ap (), - m_code_generator_ptr (NULL), - m_jit_mm_ptr (NULL), - m_execution_engine (), - m_jitted_functions () -{ - if (target_triple && target_triple[0]) - m_target_triple = target_triple; - else - m_target_triple = llvm::sys::getHostTriple(); -} - - -//---------------------------------------------------------------------- -// Destructor -//---------------------------------------------------------------------- -ClangExpression::~ClangExpression() -{ - if (m_code_generator_ptr && !m_execution_engine.get()) - delete m_code_generator_ptr; -} - -bool -ClangExpression::CreateCompilerInstance () -{ - // Initialize targets first, so that --version shows registered targets. - static struct InitializeLLVM { - InitializeLLVM() { - llvm::InitializeAllTargets(); - llvm::InitializeAllAsmPrinters(); - } - } InitializeLLVM; - - // 1. Create a new compiler instance. - m_clang_ap.reset(new CompilerInstance()); - m_clang_ap->setLLVMContext(new LLVMContext()); - - // 2. Set options. - - // Parse expressions as Objective C++ regardless of context. - // Our hook into Clang's lookup mechanism only works in C++. - m_clang_ap->getLangOpts().CPlusPlus = true; - m_clang_ap->getLangOpts().ObjC1 = true; - m_clang_ap->getLangOpts().ThreadsafeStatics = false; - m_clang_ap->getLangOpts().AccessControl = false; // Debuggers get universal access - m_clang_ap->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name - - // Set CodeGen options - m_clang_ap->getCodeGenOpts().EmitDeclMetadata = true; - m_clang_ap->getCodeGenOpts().InstrumentFunctions = false; - - // Disable some warnings. - m_clang_ap->getDiagnosticOpts().Warnings.push_back("no-unused-value"); - - // Set the target triple. - m_clang_ap->getTargetOpts().Triple = m_target_triple; - - // 3. Set up various important bits of infrastructure. - - m_clang_ap->createDiagnostics(0, 0); - - // Create the target instance. - m_clang_ap->setTarget(TargetInfo::CreateTargetInfo(m_clang_ap->getDiagnostics(), - m_clang_ap->getTargetOpts())); - if (!m_clang_ap->hasTarget()) - { - m_clang_ap.reset(); - return false; - } - - // 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_clang_ap->getTarget().setForcedLangOptions(m_clang_ap->getLangOpts()); - - return m_clang_ap.get(); -} - -Mutex & -ClangExpression::GetClangMutex () -{ - static Mutex g_clang_mutex(Mutex::eMutexTypeRecursive); // Control access to the clang compiler - return g_clang_mutex; -} - - -clang::ASTContext * -ClangExpression::GetASTContext () -{ - CompilerInstance *compiler_instance = GetCompilerInstance(); - if (compiler_instance) - return &compiler_instance->getASTContext(); - return NULL; -} - -unsigned -ClangExpression::ParseExpression (const char *expr_text, - Stream &stream, - bool add_result_var) -{ - // HACK: for now we have to make a function body around our expression - // since there is no way to parse a single expression line in LLVM/Clang. - std::string func_expr("extern \"C\" void ___clang_expr(void *___clang_arg)\n{\n\t"); - func_expr.append(expr_text); - func_expr.append(";\n}"); - return ParseBareExpression (func_expr, stream, add_result_var); - -} - -unsigned -ClangExpression::ParseBareExpression (llvm::StringRef expr_text, - Stream &stream, - bool add_result_var) -{ - Mutex::Locker locker(GetClangMutex ()); - - TextDiagnosticBuffer text_diagnostic_buffer; - - if (!CreateCompilerInstance ()) - { - stream.Printf("error: couldn't create compiler instance\n"); - return 1; - } - - // This code is matched below by a setClient to NULL. - // We cannot return out of this code without doing that. - m_clang_ap->getDiagnostics().setClient(&text_diagnostic_buffer); - text_diagnostic_buffer.FlushDiagnostics (m_clang_ap->getDiagnostics()); - - MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__); - - if (!m_clang_ap->hasSourceManager()) - m_clang_ap->createSourceManager(); - - m_clang_ap->createFileManager(); - m_clang_ap->createPreprocessor(); - - // Build the ASTContext. Most of this we inherit from the - // CompilerInstance, but we also want to give the context - // an ExternalASTSource. - SelectorTable selector_table; - std::auto_ptr<Builtin::Context> builtin_ap(new Builtin::Context(m_clang_ap->getTarget())); - ASTContext *Context = new ASTContext(m_clang_ap->getLangOpts(), - m_clang_ap->getSourceManager(), - m_clang_ap->getTarget(), - m_clang_ap->getPreprocessor().getIdentifierTable(), - selector_table, - *builtin_ap.get(), - 0); - - llvm::OwningPtr<ExternalASTSource> ASTSource(new ClangASTSource(*Context, *m_decl_map)); - - if (m_decl_map) - { - Context->setExternalSource(ASTSource); - } - - m_clang_ap->setASTContext(Context); - - FileID memory_buffer_file_id = m_clang_ap->getSourceManager().createMainFileIDForMemBuffer (memory_buffer); - std::string module_name("test_func"); - text_diagnostic_buffer.BeginSourceFile(m_clang_ap->getLangOpts(), &m_clang_ap->getPreprocessor()); - - if (m_code_generator_ptr) - delete m_code_generator_ptr; - - m_code_generator_ptr = CreateLLVMCodeGen(m_clang_ap->getDiagnostics(), - module_name, - m_clang_ap->getCodeGenOpts(), - m_clang_ap->getLLVMContext()); - - - // - CodeGeneration ASTConsumer (include/clang/ModuleBuilder.h), which will be passed in when you call... - // - Call clang::ParseAST (in lib/Sema/ParseAST.cpp) to parse the buffer. The CodeGenerator will generate code for __dbg_expr. - // - Once ParseAST completes, you can grab the llvm::Module from the CodeGenerator, which will have an llvm::Function you can hand off to the JIT. - - if (add_result_var) - { - ClangResultSynthesizer result_synthesizer(m_code_generator_ptr); - ParseAST(m_clang_ap->getPreprocessor(), &result_synthesizer, m_clang_ap->getASTContext()); - } - else - { - ParseAST(m_clang_ap->getPreprocessor(), m_code_generator_ptr, m_clang_ap->getASTContext()); - } - - - text_diagnostic_buffer.EndSourceFile(); - - //compiler_instance->getASTContext().getTranslationUnitDecl()->dump(); - - //if (compiler_instance->getFrontendOpts().ShowStats) { - // compiler_instance->getFileManager().PrintStats(); - // fprintf(stderr, "\n"); - //} - - // This code resolves the setClient above. - m_clang_ap->getDiagnostics().setClient(0); - - TextDiagnosticBuffer::const_iterator diag_iterator; - - int num_errors = 0; - -#ifdef COUNT_WARNINGS_AND_ERRORS - int num_warnings = 0; - - for (diag_iterator = text_diagnostic_buffer.warn_begin(); - diag_iterator != text_diagnostic_buffer.warn_end(); - ++diag_iterator) - num_warnings++; - - for (diag_iterator = text_diagnostic_buffer.err_begin(); - diag_iterator != text_diagnostic_buffer.err_end(); - ++diag_iterator) - num_errors++; - - if (num_warnings || num_errors) - { - if (num_warnings) - stream.Printf("%u warning%s%s", num_warnings, (num_warnings == 1 ? "" : "s"), (num_errors ? " and " : "")); - if (num_errors) - stream.Printf("%u error%s", num_errors, (num_errors == 1 ? "" : "s")); - stream.Printf("\n"); - } -#endif - - for (diag_iterator = text_diagnostic_buffer.warn_begin(); - diag_iterator != text_diagnostic_buffer.warn_end(); - ++diag_iterator) - stream.Printf("warning: %s\n", (*diag_iterator).second.c_str()); - - num_errors = 0; - - for (diag_iterator = text_diagnostic_buffer.err_begin(); - diag_iterator != text_diagnostic_buffer.err_end(); - ++diag_iterator) - { - num_errors++; - stream.Printf("error: %s\n", (*diag_iterator).second.c_str()); - } - - return num_errors; -} - -bool -ClangExpression::ConvertIRToDWARF (ClangExpressionVariableList &expr_local_variable_list, - StreamString &dwarf_opcode_strm) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - llvm::Module *module = m_code_generator_ptr->GetModule(); - - if (!module) - { - if (log) - log->Printf("IR doesn't contain a module"); - - return 1; - } - - IRToDWARF ir_to_dwarf(expr_local_variable_list, m_decl_map, dwarf_opcode_strm); - - return ir_to_dwarf.runOnModule(*module); -} - -bool -ClangExpression::PrepareIRForTarget () -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - llvm::Module *module = m_code_generator_ptr->GetModule(); - - if (!module) - { - if (log) - log->Printf("IR doesn't contain a module"); - - return 1; - } - - llvm::Triple target_triple = m_clang_ap->getTarget().getTriple(); - - std::string err; - - const llvm::Target *target = llvm::TargetRegistry::lookupTarget(m_target_triple, err); - - if (!target) - { - if (log) - log->Printf("Couldn't find a target for %s", m_target_triple.c_str()); - - return 1; - } - - std::auto_ptr<llvm::TargetMachine> target_machine(target->createTargetMachine(m_target_triple, "")); - - IRForTarget ir_for_target(m_decl_map, target_machine->getTargetData()); - - return ir_for_target.runOnModule(*module); -} - -bool -ClangExpression::JITFunction (const char *name) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - llvm::Module *module = m_code_generator_ptr->GetModule(); - - if (module) - { - std::string error; - - if (m_jit_mm_ptr == NULL) - m_jit_mm_ptr = new RecordingMemoryManager(); - - //llvm::InitializeNativeTarget(); - - if (log) - { - const char *relocation_model_string; - - switch (llvm::TargetMachine::getRelocationModel()) - { - case llvm::Reloc::Default: - relocation_model_string = "Default"; - break; - case llvm::Reloc::Static: - relocation_model_string = "Static"; - break; - case llvm::Reloc::PIC_: - relocation_model_string = "PIC_"; - break; - case llvm::Reloc::DynamicNoPIC: - relocation_model_string = "DynamicNoPIC"; - break; - } - - log->Printf("Target machine's relocation model: %s", relocation_model_string); - } - - if (m_execution_engine.get() == 0) - m_execution_engine.reset(llvm::ExecutionEngine::createJIT (module, - &error, - m_jit_mm_ptr, - CodeGenOpt::Default, - true, - CodeModel::Small)); // set to small so RIP-relative relocations work in PIC - - m_execution_engine->DisableLazyCompilation(); - llvm::Function *function = module->getFunction (llvm::StringRef (name)); - - // We don't actually need the function pointer here, this just forces it to get resolved. - void *fun_ptr = m_execution_engine->getPointerToFunction(function); - // Note, you probably won't get here on error, since the LLVM JIT tends to just - // exit on error at present... So be careful. - if (fun_ptr == 0) - return false; - m_jitted_functions.push_back(ClangExpression::JittedFunction(name, (lldb::addr_t) fun_ptr)); - - } - return true; -} - -bool -ClangExpression::WriteJITCode (const ExecutionContext &exc_context) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - if (m_jit_mm_ptr == NULL) - return false; - - if (exc_context.process == NULL) - return false; - - // Look over the regions allocated for the function compiled. The JIT - // tries to allocate the functions & stubs close together, so we should try to - // write them that way too... - // For now I only write functions with no stubs, globals, exception tables, - // etc. So I only need to write the functions. - - size_t alloc_size = 0; - std::map<uint8_t *, uint8_t *>::iterator fun_pos, fun_end = m_jit_mm_ptr->m_functions.end(); - for (fun_pos = m_jit_mm_ptr->m_functions.begin(); fun_pos != fun_end; fun_pos++) - { - alloc_size += (*fun_pos).second - (*fun_pos).first; - } - - Error error; - lldb::addr_t target_addr = exc_context.process->AllocateMemory (alloc_size, lldb::ePermissionsReadable|lldb::ePermissionsExecutable, error); - - if (target_addr == LLDB_INVALID_ADDRESS) - return false; - - lldb::addr_t cursor = target_addr; - for (fun_pos = m_jit_mm_ptr->m_functions.begin(); fun_pos != fun_end; fun_pos++) - { - if (log) - log->Printf("Reading [%p-%p] from m_functions", fun_pos->first, fun_pos->second); - - lldb::addr_t lstart = (lldb::addr_t) (*fun_pos).first; - lldb::addr_t lend = (lldb::addr_t) (*fun_pos).second; - size_t size = lend - lstart; - exc_context.process->WriteMemory(cursor, (void *) lstart, size, error); - m_jit_mm_ptr->AddToLocalToRemoteMap (lstart, size, cursor); - cursor += size; - } - - std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); - - for (pos = m_jitted_functions.begin(); pos != end; pos++) - { - (*pos).m_remote_addr = m_jit_mm_ptr->GetRemoteAddressForLocal ((*pos).m_local_addr); - } - return true; -} - -lldb::addr_t -ClangExpression::GetFunctionAddress (const char *name) -{ - std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); - - for (pos = m_jitted_functions.begin(); pos < end; pos++) - { - if (strcmp ((*pos).m_name.c_str(), name) == 0) - return (*pos).m_remote_addr; - } - return LLDB_INVALID_ADDRESS; -} - -Error -ClangExpression::DisassembleFunction (Stream &stream, ExecutionContext &exe_ctx, const char *name) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - - Error ret; - - ret.Clear(); - - lldb::addr_t func_local_addr = LLDB_INVALID_ADDRESS; - lldb::addr_t func_remote_addr = LLDB_INVALID_ADDRESS; - - std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); - - for (pos = m_jitted_functions.begin(); pos < end; pos++) - { - if (strcmp(pos->m_name.c_str(), name) == 0) - { - func_local_addr = pos->m_local_addr; - func_remote_addr = pos->m_remote_addr; - } - } - - if (func_local_addr == LLDB_INVALID_ADDRESS) - { - ret.SetErrorToGenericError(); - ret.SetErrorStringWithFormat("Couldn't find function %s for disassembly", name); - return ret; - } - - if(log) - log->Printf("Found function, has local address 0x%llx and remote address 0x%llx", (uint64_t)func_local_addr, (uint64_t)func_remote_addr); - - std::pair <lldb::addr_t, lldb::addr_t> func_range; - - func_range = m_jit_mm_ptr->GetRemoteRangeForLocal(func_local_addr); - - if (func_range.first == 0 && func_range.second == 0) - { - ret.SetErrorToGenericError(); - ret.SetErrorStringWithFormat("Couldn't find code range for function %s", name); - return ret; - } - - if(log) - log->Printf("Function's code range is [0x%llx-0x%llx]", func_range.first, func_range.second); - - if (!exe_ctx.target) - { - ret.SetErrorToGenericError(); - ret.SetErrorString("Couldn't find the target"); - } - - lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second - func_remote_addr, 0)); - - Error err; - exe_ctx.process->ReadMemory(func_remote_addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), err); - - if (!err.Success()) - { - ret.SetErrorToGenericError(); - ret.SetErrorStringWithFormat("Couldn't read from process: %s", err.AsCString("unknown error")); - return ret; - } - - ArchSpec arch(exe_ctx.target->GetArchitecture()); - - Disassembler *disassembler = Disassembler::FindPlugin(arch); - - if (disassembler == NULL) - { - ret.SetErrorToGenericError(); - ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.AsCString()); - return ret; - } - - if (!exe_ctx.process) - { - ret.SetErrorToGenericError(); - ret.SetErrorString("Couldn't find the process"); - return ret; - } - - DataExtractor extractor(buffer_sp, - exe_ctx.process->GetByteOrder(), - exe_ctx.target->GetArchitecture().GetAddressByteSize()); - - if(log) - { - log->Printf("Function data has contents:"); - extractor.PutToLog (log, - 0, - extractor.GetByteSize(), - func_remote_addr, - 16, - DataExtractor::TypeUInt8); - } - - disassembler->DecodeInstructions(extractor, 0, UINT32_MAX); - - Disassembler::InstructionList &instruction_list = disassembler->GetInstructionList(); - - uint32_t bytes_offset = 0; - - for (uint32_t instruction_index = 0, num_instructions = instruction_list.GetSize(); - instruction_index < num_instructions; - ++instruction_index) - { - Disassembler::Instruction *instruction = instruction_list.GetInstructionAtIndex(instruction_index); - Address addr(NULL, func_remote_addr + bytes_offset); - instruction->Dump (&stream, - &addr, - &extractor, - bytes_offset, - exe_ctx, - true); - stream.PutChar('\n'); - bytes_offset += instruction->GetByteSize(); - } - - return ret; -} diff --git a/lldb/source/Expression/ClangExpressionParser.cpp b/lldb/source/Expression/ClangExpressionParser.cpp new file mode 100644 index 00000000000..05c237afdb9 --- /dev/null +++ b/lldb/source/Expression/ClangExpressionParser.cpp @@ -0,0 +1,640 @@ +//===-- ClangExpressionParser.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Expression/ClangExpressionParser.h" + +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Stream.h" +#include "lldb/Expression/ClangASTSource.h" +#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/IRForTarget.h" +#include "lldb/Expression/IRToDWARF.h" +#include "lldb/Expression/RecordingMemoryManager.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/Version.h" +#include "clang/Checker/FrontendActions.h" +#include "clang/CodeGen/CodeGenAction.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Driver/CC1Options.h" +#include "clang/Driver/OptTable.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Rewrite/FrontendActions.h" +#include "clang/Sema/ParseAST.h" +#include "clang/Sema/SemaConsumer.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/JIT.h" +#include "llvm/Module.h" +#include "llvm/LLVMContext.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/DynamicLibrary.h" +#include "llvm/System/Host.h" +#include "llvm/System/Signals.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetSelect.h" + +using namespace clang; +using namespace llvm; +using namespace lldb_private; + +//===----------------------------------------------------------------------===// +// Utility Methods for Clang +//===----------------------------------------------------------------------===// + +std::string GetBuiltinIncludePath(const char *Argv0) { + llvm::sys::Path P = + llvm::sys::Path::GetMainExecutable(Argv0, + (void*)(intptr_t) GetBuiltinIncludePath); + + if (!P.isEmpty()) { + P.eraseComponent(); // Remove /clang from foo/bin/clang + P.eraseComponent(); // Remove /bin from foo/bin + + // Get foo/lib/clang/<version>/include + P.appendComponent("lib"); + P.appendComponent("clang"); + P.appendComponent(CLANG_VERSION_STRING); + P.appendComponent("include"); + } + + return P.str(); +} + + +//===----------------------------------------------------------------------===// +// Main driver for Clang +//===----------------------------------------------------------------------===// + +static void LLVMErrorHandler(void *UserData, const std::string &Message) { + Diagnostic &Diags = *static_cast<Diagnostic*>(UserData); + + Diags.Report(diag::err_fe_error_backend) << Message; + + // We cannot recover from llvm errors. + exit(1); +} + +static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { + using namespace clang::frontend; + + switch (CI.getFrontendOpts().ProgramAction) { + default: + llvm_unreachable("Invalid program action!"); + + case ASTDump: return new ASTDumpAction(); + case ASTPrint: return new ASTPrintAction(); + case ASTPrintXML: return new ASTPrintXMLAction(); + case ASTView: return new ASTViewAction(); + case BoostCon: return new BoostConAction(); + case DumpRawTokens: return new DumpRawTokensAction(); + case DumpTokens: return new DumpTokensAction(); + case EmitAssembly: return new EmitAssemblyAction(); + case EmitBC: return new EmitBCAction(); + case EmitHTML: return new HTMLPrintAction(); + case EmitLLVM: return new EmitLLVMAction(); + case EmitLLVMOnly: return new EmitLLVMOnlyAction(); + case EmitCodeGenOnly: return new EmitCodeGenOnlyAction(); + case EmitObj: return new EmitObjAction(); + case FixIt: return new FixItAction(); + case GeneratePCH: return new GeneratePCHAction(); + case GeneratePTH: return new GeneratePTHAction(); + case InheritanceView: return new InheritanceViewAction(); + case InitOnly: return new InitOnlyAction(); + case ParseSyntaxOnly: return new SyntaxOnlyAction(); + + case PluginAction: { + for (FrontendPluginRegistry::iterator it = + FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); + it != ie; ++it) { + if (it->getName() == CI.getFrontendOpts().ActionName) { + llvm::OwningPtr<PluginASTAction> P(it->instantiate()); + if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs)) + return 0; + return P.take(); + } + } + + CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) + << CI.getFrontendOpts().ActionName; + return 0; + } + + case PrintDeclContext: return new DeclContextPrintAction(); + case PrintPreamble: return new PrintPreambleAction(); + case PrintPreprocessedInput: return new PrintPreprocessedAction(); + case RewriteMacros: return new RewriteMacrosAction(); + case RewriteObjC: return new RewriteObjCAction(); + case RewriteTest: return new RewriteTestAction(); + case RunAnalysis: return new AnalysisAction(); + case RunPreprocessorOnly: return new PreprocessOnlyAction(); + } +} + +static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { + // Create the underlying action. + FrontendAction *Act = CreateFrontendBaseAction(CI); + if (!Act) + return 0; + + // If there are any AST files to merge, create a frontend action + // adaptor to perform the merge. + if (!CI.getFrontendOpts().ASTMergeFiles.empty()) + Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0], + CI.getFrontendOpts().ASTMergeFiles.size()); + + return Act; +} + +//===----------------------------------------------------------------------===// +// Implementation of ClangExpressionParser +//===----------------------------------------------------------------------===// + +ClangExpressionParser::ClangExpressionParser(const char *target_triple, + ClangExpression &expr) : + m_expr(expr), + m_target_triple (), + m_compiler (), + m_code_generator (NULL), + m_execution_engine (), + m_jitted_functions () +{ + // Initialize targets first, so that --version shows registered targets. + static struct InitializeLLVM { + InitializeLLVM() { + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + } + } InitializeLLVM; + + if (target_triple && target_triple[0]) + m_target_triple = target_triple; + else + m_target_triple = llvm::sys::getHostTriple(); + + // 1. Create a new compiler instance. + m_compiler.reset(new CompilerInstance()); + m_compiler->setLLVMContext(new LLVMContext()); + + // 2. Set options. + + // Parse expressions as Objective C++ regardless of context. + // Our hook into Clang's lookup mechanism only works in C++. + m_compiler->getLangOpts().CPlusPlus = true; + m_compiler->getLangOpts().ObjC1 = 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; + + // Disable some warnings. + m_compiler->getDiagnosticOpts().Warnings.push_back("no-unused-value"); + + // Set the target triple. + m_compiler->getTargetOpts().Triple = m_target_triple; + + // 3. Set up various important bits of infrastructure. + m_compiler->createDiagnostics(0, 0); + + // Create the target instance. + m_compiler->setTarget(TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(), + m_compiler->getTargetOpts())); + + assert (m_compiler->hasTarget()); + + // 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().setForcedLangOptions(m_compiler->getLangOpts()); + + // 4. Set up the diagnostic buffer for reporting errors + + m_diagnostic_buffer.reset(new clang::TextDiagnosticBuffer); + m_compiler->getDiagnostics().setClient(m_diagnostic_buffer.get()); + + // 5. Set up the source management objects inside the compiler + + if (!m_compiler->hasSourceManager()) + m_compiler->createSourceManager(); + + m_compiler->createFileManager(); + m_compiler->createPreprocessor(); + + // 6. Most of this we get from the CompilerInstance, but we + // also want to give the context an ExternalASTSource. + SelectorTable selector_table; + m_builtin_context.reset(new Builtin::Context(m_compiler->getTarget())); + + std::auto_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(), + m_compiler->getSourceManager(), + m_compiler->getTarget(), + m_compiler->getPreprocessor().getIdentifierTable(), + selector_table, + *m_builtin_context.get(), + 0)); + + ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); + + if (decl_map) + { + OwningPtr<clang::ExternalASTSource> ast_source(new ClangASTSource(*ast_context, *decl_map)); + ast_context->setExternalSource(ast_source); + } + + m_compiler->setASTContext(ast_context.release()); + + std::string module_name("___clang_module"); + + m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(), + module_name, + m_compiler->getCodeGenOpts(), + m_compiler->getLLVMContext())); +} + +ClangExpressionParser::~ClangExpressionParser() +{ +} + +unsigned +ClangExpressionParser::Parse (Stream &stream) +{ + m_diagnostic_buffer->FlushDiagnostics (m_compiler->getDiagnostics()); + + MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(m_expr.Text(), __FUNCTION__); + FileID memory_buffer_file_id = m_compiler->getSourceManager().createMainFileIDForMemBuffer (memory_buffer); + + m_diagnostic_buffer->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor()); + + ASTConsumer *ast_transformer = m_expr.ASTTransformer(m_code_generator.get()); + + if (ast_transformer) + ParseAST(m_compiler->getPreprocessor(), ast_transformer, m_compiler->getASTContext()); + else + ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), m_compiler->getASTContext()); + + m_diagnostic_buffer->EndSourceFile(); + + TextDiagnosticBuffer::const_iterator diag_iterator; + + int num_errors = 0; + + for (diag_iterator = m_diagnostic_buffer->warn_begin(); + diag_iterator != m_diagnostic_buffer->warn_end(); + ++diag_iterator) + stream.Printf("warning: %s\n", (*diag_iterator).second.c_str()); + + num_errors = 0; + + for (diag_iterator = m_diagnostic_buffer->err_begin(); + diag_iterator != m_diagnostic_buffer->err_end(); + ++diag_iterator) + { + num_errors++; + stream.Printf("error: %s\n", (*diag_iterator).second.c_str()); + } + + return num_errors; +} + +Error +ClangExpressionParser::MakeDWARF () +{ + Error err; + + llvm::Module *module = m_code_generator->GetModule(); + + if (!module) + { + err.SetErrorToGenericError(); + err.SetErrorString("IR doesn't contain a module"); + return err; + } + + ClangExpressionVariableStore *local_variables = m_expr.LocalVariables(); + ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); + + if (!local_variables) + { + err.SetErrorToGenericError(); + err.SetErrorString("Can't convert an expression without a VariableList to DWARF"); + return err; + } + + if (!decl_map) + { + err.SetErrorToGenericError(); + err.SetErrorString("Can't convert an expression without a DeclMap to DWARF"); + return err; + } + + IRToDWARF ir_to_dwarf(*local_variables, decl_map, m_expr.DwarfOpcodeStream()); + + if (!ir_to_dwarf.runOnModule(*module)) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't convert the expression to DWARF"); + return err; + } + + err.Clear(); + return err; +} + +Error +ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr, ExecutionContext &exe_ctx) +{ + Error err; + + llvm::Module *module = m_code_generator->ReleaseModule(); + + if (!module) + { + err.SetErrorToGenericError(); + err.SetErrorString("IR doesn't contain a module"); + return err; + } + + ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); // result can be NULL + + if (decl_map) + { + std::string target_error; + + const llvm::Target *target = llvm::TargetRegistry::lookupTarget(m_target_triple, target_error); + + if (!target) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't find a target for %s", m_target_triple.c_str()); + return err; + } + + std::auto_ptr<llvm::TargetMachine> target_machine(target->createTargetMachine(m_target_triple, "")); + + IRForTarget ir_for_target(decl_map, target_machine->getTargetData(), m_expr.FunctionName()); + + if (!ir_for_target.runOnModule(*module)) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't convert the expression to DWARF"); + return err; + } + } + + m_jit_mm = new RecordingMemoryManager(); + + std::string error_string; + + m_execution_engine.reset(llvm::ExecutionEngine::createJIT (module, + &error_string, + m_jit_mm, + CodeGenOpt::Default, + true, + CodeModel::Small)); + + if (!m_execution_engine.get()) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str()); + return err; + } + + m_execution_engine->DisableLazyCompilation(); + + llvm::Function *function = module->getFunction (m_expr.FunctionName()); + + // We don't actually need the function pointer here, this just forces it to get resolved. + + void *fun_ptr = m_execution_engine->getPointerToFunction(function); + + // Errors usually cause failures in the JIT, but if we're lucky we get here. + + if (!fun_ptr) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't JIT the function"); + return err; + } + + m_jitted_functions.push_back (ClangExpressionParser::JittedFunction(m_expr.FunctionName(), (lldb::addr_t)fun_ptr)); + + ExecutionContext &exc_context(exe_ctx); + + if (exc_context.process == NULL) + { + err.SetErrorToGenericError(); + err.SetErrorString("Couldn't write the JIT compiled code into the target because there is no target"); + return err; + } + + // Look over the regions allocated for the function compiled. The JIT + // tries to allocate the functions & stubs close together, so we should try to + // write them that way too... + // For now I only write functions with no stubs, globals, exception tables, + // etc. So I only need to write the functions. + + size_t alloc_size = 0; + + std::map<uint8_t *, uint8_t *>::iterator fun_pos = m_jit_mm->m_functions.begin(); + std::map<uint8_t *, uint8_t *>::iterator fun_end = m_jit_mm->m_functions.end(); + + for (; fun_pos != fun_end; ++fun_pos) + alloc_size += (*fun_pos).second - (*fun_pos).first; + + Error alloc_error; + lldb::addr_t target_addr = exc_context.process->AllocateMemory (alloc_size, lldb::ePermissionsReadable|lldb::ePermissionsExecutable, alloc_error); + + if (target_addr == LLDB_INVALID_ADDRESS) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't allocate memory for the JITted function: %s", alloc_error.AsCString("unknown error")); + return err; + } + + lldb::addr_t cursor = target_addr; + + for (fun_pos = m_jit_mm->m_functions.begin(); fun_pos != fun_end; fun_pos++) + { + lldb::addr_t lstart = (lldb::addr_t) (*fun_pos).first; + lldb::addr_t lend = (lldb::addr_t) (*fun_pos).second; + size_t size = lend - lstart; + + Error write_error; + + if (exc_context.process->WriteMemory(cursor, (void *) lstart, size, write_error) != size) + { + err.SetErrorToGenericError(); + err.SetErrorStringWithFormat("Couldn't copy JITted function into the target: %s", write_error.AsCString("unknown error")); + return err; + } + + m_jit_mm->AddToLocalToRemoteMap (lstart, size, cursor); + cursor += size; + } + + std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); + + for (pos = m_jitted_functions.begin(); pos != end; pos++) + { + (*pos).m_remote_addr = m_jit_mm->GetRemoteAddressForLocal ((*pos).m_local_addr); + + if (!(*pos).m_name.compare(m_expr.FunctionName())) + func_addr = (*pos).m_remote_addr; + } + + err.Clear(); + return err; +} + +Error +ClangExpressionParser::DisassembleFunction (Stream &stream, ExecutionContext &exe_ctx) +{ + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); + + const char *name = m_expr.FunctionName(); + + Error ret; + + ret.Clear(); + + lldb::addr_t func_local_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t func_remote_addr = LLDB_INVALID_ADDRESS; + + std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); + + for (pos = m_jitted_functions.begin(); pos < end; pos++) + { + if (strcmp(pos->m_name.c_str(), name) == 0) + { + func_local_addr = pos->m_local_addr; + func_remote_addr = pos->m_remote_addr; + } + } + + if (func_local_addr == LLDB_INVALID_ADDRESS) + { + ret.SetErrorToGenericError(); + ret.SetErrorStringWithFormat("Couldn't find function %s for disassembly", name); + return ret; + } + + if(log) + log->Printf("Found function, has local address 0x%llx and remote address 0x%llx", (uint64_t)func_local_addr, (uint64_t)func_remote_addr); + + std::pair <lldb::addr_t, lldb::addr_t> func_range; + + func_range = m_jit_mm->GetRemoteRangeForLocal(func_local_addr); + + if (func_range.first == 0 && func_range.second == 0) + { + ret.SetErrorToGenericError(); + ret.SetErrorStringWithFormat("Couldn't find code range for function %s", name); + return ret; + } + + if(log) + log->Printf("Function's code range is [0x%llx-0x%llx]", func_range.first, func_range.second); + + if (!exe_ctx.target) + { + ret.SetErrorToGenericError(); + ret.SetErrorString("Couldn't find the target"); + } + + lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second - func_remote_addr, 0)); + + Error err; + exe_ctx.process->ReadMemory(func_remote_addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), err); + + if (!err.Success()) + { + ret.SetErrorToGenericError(); + ret.SetErrorStringWithFormat("Couldn't read from process: %s", err.AsCString("unknown error")); + return ret; + } + + ArchSpec arch(exe_ctx.target->GetArchitecture()); + + Disassembler *disassembler = Disassembler::FindPlugin(arch); + + if (disassembler == NULL) + { + ret.SetErrorToGenericError(); + ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.AsCString()); + return ret; + } + + if (!exe_ctx.process) + { + ret.SetErrorToGenericError(); + ret.SetErrorString("Couldn't find the process"); + return ret; + } + + DataExtractor extractor(buffer_sp, + exe_ctx.process->GetByteOrder(), + exe_ctx.target->GetArchitecture().GetAddressByteSize()); + + if(log) + { + log->Printf("Function data has contents:"); + extractor.PutToLog (log, + 0, + extractor.GetByteSize(), + func_remote_addr, + 16, + DataExtractor::TypeUInt8); + } + + disassembler->DecodeInstructions(extractor, 0, UINT32_MAX); + + Disassembler::InstructionList &instruction_list = disassembler->GetInstructionList(); + + uint32_t bytes_offset = 0; + + for (uint32_t instruction_index = 0, num_instructions = instruction_list.GetSize(); + instruction_index < num_instructions; + ++instruction_index) + { + Disassembler::Instruction *instruction = instruction_list.GetInstructionAtIndex(instruction_index); + Address addr(NULL, func_remote_addr + bytes_offset); + instruction->Dump (&stream, + &addr, + &extractor, + bytes_offset, + exe_ctx, + true); + stream.PutChar('\n'); + bytes_offset += instruction->GetByteSize(); + } + + return ret; +} diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index 5d3e4c8ca0d..be107ca8eb0 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -22,6 +22,8 @@ #include "llvm/Module.h" // Project includes +#include "lldb/Expression/ASTStructExtractor.h" +#include "lldb/Expression/ClangExpressionParser.h" #include "lldb/Expression/ClangFunction.h" #include "lldb/Symbol/Type.h" #include "lldb/Core/DataExtractor.h" @@ -40,11 +42,12 @@ #include "lldb/Core/Log.h" using namespace lldb_private; + //---------------------------------------------------------------------- // ClangFunction constructor //---------------------------------------------------------------------- ClangFunction::ClangFunction(const char *target_triple, ClangASTContext *ast_context, void *return_qualtype, const Address& functionAddress, const ValueList &arg_value_list) : - ClangExpression (target_triple, NULL), + m_target_triple (target_triple), m_function_ptr (NULL), m_function_addr (functionAddress), m_function_return_qual_type(return_qualtype), @@ -53,18 +56,14 @@ ClangFunction::ClangFunction(const char *target_triple, ClangASTContext *ast_con m_wrapper_struct_name ("__lldb_caller_struct"), m_wrapper_function_addr (), m_wrapper_args_addrs (), - m_struct_layout (NULL), m_arg_values (arg_value_list), - m_value_struct_size (0), - m_return_offset(0), - m_return_size (0), m_compiled (false), m_JITted (false) { } ClangFunction::ClangFunction(const char *target_triple, Function &function, ClangASTContext *ast_context, const ValueList &arg_value_list) : - ClangExpression (target_triple, NULL), + m_target_triple (target_triple), m_function_ptr (&function), m_function_addr (), m_function_return_qual_type (), @@ -73,11 +72,7 @@ ClangFunction::ClangFunction(const char *target_triple, Function &function, Clan m_wrapper_struct_name ("__lldb_caller_struct"), m_wrapper_function_addr (), m_wrapper_args_addrs (), - m_struct_layout (NULL), m_arg_values (arg_value_list), - m_value_struct_size (0), - m_return_offset (0), - m_return_size (0), m_compiled (false), m_JITted (false) { @@ -95,154 +90,125 @@ ClangFunction::~ClangFunction() unsigned ClangFunction::CompileFunction (Stream &errors) { + if (m_compiled) + return 0; + // FIXME: How does clang tell us there's no return value? We need to handle that case. unsigned num_errors = 0; - if (!m_compiled) + std::string return_type_str = ClangASTContext::GetTypeName(m_function_return_qual_type); + + // Cons up the function we're going to wrap our call in, then compile it... + // We declare the function "extern "C"" because the compiler might be in C++ + // mode which would mangle the name and then we couldn't find it again... + m_wrapper_function_text.clear(); + m_wrapper_function_text.append ("extern \"C\" void "); + m_wrapper_function_text.append (m_wrapper_function_name); + m_wrapper_function_text.append (" (void *input)\n{\n struct "); + m_wrapper_function_text.append (m_wrapper_struct_name); + m_wrapper_function_text.append (" \n {\n"); + m_wrapper_function_text.append (" "); + m_wrapper_function_text.append (return_type_str); + m_wrapper_function_text.append (" (*fn_ptr) ("); + + // Get the number of arguments. If we have a function type and it is prototyped, + // trust that, otherwise use the values we were given. + + // FIXME: This will need to be extended to handle Variadic functions. We'll need + // to pull the defined arguments out of the function, then add the types from the + // arguments list for the variable arguments. + + uint32_t num_args = UINT32_MAX; + bool trust_function = false; + // GetArgumentCount returns -1 for an unprototyped function. + if (m_function_ptr) { - std::string return_type_str = ClangASTContext::GetTypeName(m_function_return_qual_type); - - // Cons up the function we're going to wrap our call in, then compile it... - // We declare the function "extern "C"" because the compiler might be in C++ - // mode which would mangle the name and then we couldn't find it again... - std::string expression; - expression.append ("extern \"C\" void "); - expression.append (m_wrapper_function_name); - expression.append (" (void *input)\n{\n struct "); - expression.append (m_wrapper_struct_name); - expression.append (" \n {\n"); - expression.append (" "); - expression.append (return_type_str); - expression.append (" (*fn_ptr) ("); - - // Get the number of arguments. If we have a function type and it is prototyped, - // trust that, otherwise use the values we were given. - - // FIXME: This will need to be extended to handle Variadic functions. We'll need - // to pull the defined arguments out of the function, then add the types from the - // arguments list for the variable arguments. - - uint32_t num_args = UINT32_MAX; - bool trust_function = false; - // GetArgumentCount returns -1 for an unprototyped function. - if (m_function_ptr) - { - int num_func_args = m_function_ptr->GetArgumentCount(); - if (num_func_args >= 0) - trust_function = true; - else - num_args = num_func_args; - } + int num_func_args = m_function_ptr->GetArgumentCount(); + if (num_func_args >= 0) + trust_function = true; + else + num_args = num_func_args; + } - if (num_args == UINT32_MAX) - num_args = m_arg_values.GetSize(); + if (num_args == UINT32_MAX) + num_args = m_arg_values.GetSize(); - std::string args_buffer; // This one stores the definition of all the args in "struct caller". - std::string args_list_buffer; // This one stores the argument list called from the structure. - for (size_t i = 0; i < num_args; i++) - { - const char *type_string; - std::string type_stdstr; + std::string args_buffer; // This one stores the definition of all the args in "struct caller". + std::string args_list_buffer; // This one stores the argument list called from the structure. + for (size_t i = 0; i < num_args; i++) + { + const char *type_string; + std::string type_stdstr; - if (trust_function) + if (trust_function) + { + type_string = m_function_ptr->GetArgumentTypeAtIndex(i).GetName().AsCString(); + } + else + { + Value *arg_value = m_arg_values.GetValueAtIndex(i); + void *clang_qual_type = arg_value->GetOpaqueClangQualType (); + if (clang_qual_type != NULL) { - type_string = m_function_ptr->GetArgumentTypeAtIndex(i).GetName().AsCString(); + type_stdstr = ClangASTContext::GetTypeName(clang_qual_type); + type_string = type_stdstr.c_str(); } else - { - Value *arg_value = m_arg_values.GetValueAtIndex(i); - void *clang_qual_type = arg_value->GetOpaqueClangQualType (); - if (clang_qual_type != NULL) - { - type_stdstr = ClangASTContext::GetTypeName(clang_qual_type); - type_string = type_stdstr.c_str(); - } - else - { - errors.Printf("Could not determine type of input value %d.", i); - return 1; - } + { + errors.Printf("Could not determine type of input value %d.", i); + return 1; } + } + m_wrapper_function_text.append (type_string); + if (i < num_args - 1) + m_wrapper_function_text.append (", "); - expression.append (type_string); - if (i < num_args - 1) - expression.append (", "); - - char arg_buf[32]; - args_buffer.append (" "); - args_buffer.append (type_string); - snprintf(arg_buf, 31, "arg_%zd", i); - args_buffer.push_back (' '); - args_buffer.append (arg_buf); - args_buffer.append (";\n"); - - args_list_buffer.append ("__lldb_fn_data->"); - args_list_buffer.append (arg_buf); - if (i < num_args - 1) - args_list_buffer.append (", "); - - } - expression.append (");\n"); // Close off the function calling prototype. - - expression.append (args_buffer); - - expression.append (" "); - expression.append (return_type_str); - expression.append (" return_value;"); - expression.append ("\n };\n struct "); - expression.append (m_wrapper_struct_name); - expression.append ("* __lldb_fn_data = (struct "); - expression.append (m_wrapper_struct_name); - expression.append (" *) input;\n"); - - expression.append (" __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr ("); - expression.append (args_list_buffer); - expression.append (");\n}\n"); - - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); - if (log) - log->Printf ("Expression: \n\n%s\n\n", expression.c_str()); - - // Okay, now compile this expression: - num_errors = ParseBareExpression (expression.c_str(), errors); - m_compiled = (num_errors == 0); - - if (m_compiled) - { - using namespace clang; - CompilerInstance *compiler_instance = GetCompilerInstance(); - ASTContext &ast_context = compiler_instance->getASTContext(); + char arg_buf[32]; + args_buffer.append (" "); + args_buffer.append (type_string); + snprintf(arg_buf, 31, "arg_%zd", i); + args_buffer.push_back (' '); + args_buffer.append (arg_buf); + args_buffer.append (";\n"); - DeclarationName wrapper_func_name(&ast_context.Idents.get(m_wrapper_function_name.c_str())); - FunctionDecl::lookup_result func_lookup = ast_context.getTranslationUnitDecl()->lookup(wrapper_func_name); - if (func_lookup.first == func_lookup.second) - return false; + args_list_buffer.append ("__lldb_fn_data->"); + args_list_buffer.append (arg_buf); + if (i < num_args - 1) + args_list_buffer.append (", "); - FunctionDecl *wrapper_func = dyn_cast<FunctionDecl> (*(func_lookup.first)); - if (!wrapper_func) - return false; + } + m_wrapper_function_text.append (");\n"); // Close off the function calling prototype. - DeclarationName wrapper_struct_name(&ast_context.Idents.get(m_wrapper_struct_name.c_str())); - RecordDecl::lookup_result struct_lookup = wrapper_func->lookup(wrapper_struct_name); - if (struct_lookup.first == struct_lookup.second) - return false; + m_wrapper_function_text.append (args_buffer); - RecordDecl *wrapper_struct = dyn_cast<RecordDecl>(*(struct_lookup.first)); + m_wrapper_function_text.append (" "); + m_wrapper_function_text.append (return_type_str); + m_wrapper_function_text.append (" return_value;"); + m_wrapper_function_text.append ("\n };\n struct "); + m_wrapper_function_text.append (m_wrapper_struct_name); + m_wrapper_function_text.append ("* __lldb_fn_data = (struct "); + m_wrapper_function_text.append (m_wrapper_struct_name); + m_wrapper_function_text.append (" *) input;\n"); - if (!wrapper_struct) - return false; + m_wrapper_function_text.append (" __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr ("); + m_wrapper_function_text.append (args_list_buffer); + m_wrapper_function_text.append (");\n}\n"); - m_struct_layout = &ast_context.getASTRecordLayout (wrapper_struct); - if (!m_struct_layout) - { - m_compiled = false; - return 1; - } - m_return_offset = m_struct_layout->getFieldOffset(m_struct_layout->getFieldCount() - 1); - m_return_size = (m_struct_layout->getDataSize() - m_return_offset)/8; - } - } + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); + if (log) + log->Printf ("Expression: \n\n%s\n\n", m_wrapper_function_text.c_str()); + + // Okay, now compile this expression + + m_parser.reset(new ClangExpressionParser(m_target_triple.c_str(), *this)); + + num_errors = m_parser->Parse (errors); + + m_compiled = (num_errors == 0); + + if (!m_compiled) + return num_errors; return num_errors; } @@ -252,24 +218,18 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors) { Process *process = exe_ctx.process; - if (process == NULL) + if (!process) + return false; + + if (!m_compiled) return false; - if (!m_JITted) - { - // Next we should JIT it and insert the result into the target program. - if (!JITFunction (m_wrapper_function_name.c_str())) - return false; - - if (!WriteJITCode (exe_ctx)) - return false; - - m_JITted = true; - } - - // Next get the call address for the function: - m_wrapper_function_addr = GetFunctionAddress (m_wrapper_function_name.c_str()); - if (m_wrapper_function_addr == LLDB_INVALID_ADDRESS) + if (m_JITted) + return true; + + Error jit_error = m_parser->MakeJIT(m_wrapper_function_addr, exe_ctx); + + if (!jit_error.Success()) return false; return true; @@ -286,12 +246,14 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t & bool ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Address function_address, ValueList &arg_values, Stream &errors) { - // Otherwise, allocate space for the argument passing struct, and write it. - // We use the information in the expression parser AST to - // figure out how to do this... - // We should probably transcode this in this object so we can ditch the compiler instance - // and all its associated data, and just keep the JITTed bytes. - + // All the information to reconstruct the struct is provided by the + // StructExtractor. + if (!m_struct_valid) + { + errors.Printf("Argument information was not correctly parsed, so the function cannot be called."); + return false; + } + Error error; using namespace clang; ExecutionResults return_value = eExecutionSetupError; @@ -300,12 +262,10 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t & if (process == NULL) return return_value; - - uint64_t struct_size = m_struct_layout->getSize()/8; // Clang returns sizes in bytes. - + if (args_addr_ref == LLDB_INVALID_ADDRESS) { - args_addr_ref = process->AllocateMemory(struct_size, lldb::ePermissionsReadable|lldb::ePermissionsWritable, error); + args_addr_ref = process->AllocateMemory(m_struct_size, lldb::ePermissionsReadable|lldb::ePermissionsWritable, error); if (args_addr_ref == LLDB_INVALID_ADDRESS) return false; m_wrapper_args_addrs.push_back (args_addr_ref); @@ -323,7 +283,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t & // Make a data extractor and put the address into the right byte order & size. uint64_t fun_addr = function_address.GetLoadAddress(exe_ctx.process); - int first_offset = m_struct_layout->getFieldOffset(0)/8; + int first_offset = m_member_offsets[0]; process->WriteMemory(args_addr_ref + first_offset, &fun_addr, 8, error); // FIXME: We will need to extend this for Variadic functions. @@ -341,7 +301,7 @@ ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t & { // FIXME: We should sanity check sizes. - int offset = m_struct_layout->getFieldOffset(i+1)/8; // Clang sizes are in bytes. + int offset = m_member_offsets[i+1]; // Clang sizes are in bytes. Value *arg_value = arg_values.GetValueAtIndex(i); // FIXME: For now just do scalars: @@ -419,7 +379,7 @@ ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t arg data_buffer.resize(m_return_size); Process *process = exe_ctx.process; Error error; - size_t bytes_read = process->ReadMemory(args_addr + m_return_offset/8, &data_buffer.front(), m_return_size, error); + size_t bytes_read = process->ReadMemory(args_addr + m_return_offset, &data_buffer.front(), m_return_size, error); if (bytes_read == 0) { @@ -717,69 +677,8 @@ ClangFunction::ExecuteFunction( return eExecutionCompleted; } -ClangFunction::ExecutionResults -ClangFunction::ExecuteFunctionWithABI(ExecutionContext &exe_ctx, Stream &errors, Value &results) +clang::ASTConsumer * +ClangFunction::ASTTransformer (clang::ASTConsumer *passthrough) { - // FIXME: Use the errors Stream for better error reporting. - using namespace clang; - ExecutionResults return_value = eExecutionSetupError; - - Process *process = exe_ctx.process; - - if (process == NULL) - { - errors.Printf("Can't call a function without a process."); - return return_value; - } - - //unsigned int num_args = m_arg_values.GetSize(); - //unsigned int arg_index; - - //for (arg_index = 0; arg_index < num_args; ++arg_index) - // m_arg_values.GetValueAtIndex(arg_index)->ResolveValue(&exe_ctx, GetASTContext()); - - ThreadPlan *call_plan = exe_ctx.thread->QueueThreadPlanForCallFunction (false, - m_function_addr, - m_arg_values, - true); - if (call_plan == NULL) - return return_value; - - call_plan->SetPrivate(true); - - // We need to call the function synchronously, so spin waiting for it to return. - // If we get interrupted while executing, we're going to lose our context, and - // won't be able to gather the result at this point. - - process->Resume (); - - while (1) - { - lldb::EventSP event_sp; - - // Now wait for the process to stop again: - // FIXME: Probably want a time out. - lldb::StateType stop_state = process->WaitForStateChangedEvents (NULL, event_sp); - if (stop_state == lldb::eStateRunning || stop_state == lldb::eStateStepping) - continue; - - if (exe_ctx.thread->IsThreadPlanDone (call_plan)) - { - return_value = eExecutionCompleted; - break; - } - else if (exe_ctx.thread->WasThreadPlanDiscarded (call_plan)) - { - return_value = eExecutionDiscarded; - break; - } - else - { - return_value = eExecutionInterrupted; - break; - } - - } - - return eExecutionCompleted; + return new ASTStructExtractor(passthrough, m_wrapper_struct_name.c_str(), *this); } diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp new file mode 100644 index 00000000000..afd94bbd6a8 --- /dev/null +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -0,0 +1,257 @@ +//===-- ClangUserExpression.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +// C++ Includes +#include <cstdlib> +#include <string> +#include <map> + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Expression/ClangExpressionDeclMap.h" +#include "lldb/Expression/ClangExpressionParser.h" +#include "lldb/Expression/ClangFunction.h" +#include "lldb/Expression/ASTResultSynthesizer.h" +#include "lldb/Expression/ClangUserExpression.h" +#include "lldb/Host/Host.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Target.h" + +using namespace lldb_private; + +ClangUserExpression::ClangUserExpression (const char *expr) : + m_expr_text(expr), + m_jit_addr(LLDB_INVALID_ADDRESS) +{ + StreamString m_transformed_stream; + + m_transformed_stream.Printf("extern \"C\" void %s(void *___clang_arg) { %s; }\n", + FunctionName(), + m_expr_text.c_str()); + + m_transformed_text = m_transformed_stream.GetData(); +} + +clang::ASTConsumer * +ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough) +{ + return new ASTResultSynthesizer(passthrough); +} + +bool +ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx) +{ + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); + + //////////////////////////////////// + // Set up the target and compiler + // + + Target *target = exe_ctx.target; + + if (!target) + { + error_stream.PutCString ("error: invalid target\n"); + return false; + } + + ConstString target_triple; + + target->GetTargetTriple (target_triple); + + if (!target_triple) + target_triple = Host::GetTargetTriple (); + + if (!target_triple) + { + error_stream.PutCString ("error: invalid target triple\n"); + return false; + } + + ////////////////////////// + // Parse the expression + // + + m_expr_decl_map.reset(new ClangExpressionDeclMap(&exe_ctx)); + + ClangExpressionParser parser(target_triple.GetCString(), *this); + + unsigned num_errors = parser.Parse (error_stream); + + if (num_errors) + { + error_stream.Printf ("error: %d errors parsing expression\n", num_errors); + return false; + } + + /////////////////////////////////////////////// + // Convert the output of the parser to DWARF + // + + m_dwarf_opcodes.reset(new StreamString); + m_dwarf_opcodes->SetByteOrder (lldb::eByteOrderHost); + m_dwarf_opcodes->GetFlags ().Set (Stream::eBinary); + + m_local_variables.reset(new ClangExpressionVariableStore()); + + Error dwarf_error = parser.MakeDWARF (); + + if (dwarf_error.Success()) + { + if (log) + log->Printf("Code can be interpreted."); + + return true; + } + + ////////////////////////////////// + // JIT the output of the parser + // + + m_dwarf_opcodes.reset(); + + Error jit_error = parser.MakeJIT (m_jit_addr, exe_ctx); + + if (jit_error.Success()) + { + if (log) + { + log->Printf("Code can be run in the target."); + + StreamString disassembly_stream; + + Error err = parser.DisassembleFunction(disassembly_stream, exe_ctx); + + if (!err.Success()) + { + log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); + } + else + { + log->Printf("Function disassembly:\n%s", disassembly_stream.GetData()); + } + } + + return true; + } + else + { + error_stream.Printf ("error: expression can't be interpreted or run\n", num_errors); + return false; + } +} + +bool +ClangUserExpression::Execute (Stream &error_stream, + ExecutionContext &exe_ctx, + ClangExpressionVariable *&result) +{ + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); + + if (m_dwarf_opcodes.get()) + { + // TODO execute the JITted opcodes + + error_stream.Printf("We don't currently support executing DWARF expressions"); + + return false; + } + else if (m_jit_addr != LLDB_INVALID_ADDRESS) + { + lldb::addr_t struct_address; + + Error materialize_error; + + if (!m_expr_decl_map->Materialize(&exe_ctx, struct_address, materialize_error)) + { + error_stream.Printf("Couldn't materialize struct: %s\n", materialize_error.AsCString("unknown error")); + return false; + } + + if (log) + { + log->Printf("Function address : 0x%llx", (uint64_t)m_jit_addr); + log->Printf("Structure address : 0x%llx", (uint64_t)struct_address); + + StreamString args; + + Error dump_error; + + if (!m_expr_decl_map->DumpMaterializedStruct(&exe_ctx, args, dump_error)) + { + log->Printf("Couldn't extract variable values : %s", dump_error.AsCString("unknown error")); + } + else + { + log->Printf("Structure contents:\n%s", args.GetData()); + } + } + + ClangFunction::ExecutionResults execution_result = + ClangFunction::ExecuteFunction (exe_ctx, m_jit_addr, struct_address, true, true, 10000, error_stream); + + if (execution_result != ClangFunction::eExecutionCompleted) + { + const char *result_name; + + switch (execution_result) + { + case ClangFunction::eExecutionCompleted: + result_name = "eExecutionCompleted"; + break; + case ClangFunction::eExecutionDiscarded: + result_name = "eExecutionDiscarded"; + break; + case ClangFunction::eExecutionInterrupted: + result_name = "eExecutionInterrupted"; + break; + case ClangFunction::eExecutionSetupError: + result_name = "eExecutionSetupError"; + break; + case ClangFunction::eExecutionTimedOut: + result_name = "eExecutionTimedOut"; + break; + } + + error_stream.Printf ("Couldn't execute function; result was %s\n", result_name); + return false; + } + + Error expr_error; + + if (!m_expr_decl_map->Dematerialize(&exe_ctx, result, expr_error)) + { + error_stream.Printf ("Couldn't dematerialize struct : %s\n", expr_error.AsCString("unknown error")); + return false; + } + + return true; + } + else + { + error_stream.Printf("Expression can't be run; neither DWARF nor a JIT compiled function are present"); + return false; + } +} + +StreamString & +ClangUserExpression::DwarfOpcodeStream () +{ + if (!m_dwarf_opcodes.get()) + m_dwarf_opcodes.reset(new StreamString()); + + return *m_dwarf_opcodes.get(); +} diff --git a/lldb/source/Expression/IRForTarget.cpp b/lldb/source/Expression/IRForTarget.cpp index c14891b160c..d74302c7299 100644 --- a/lldb/source/Expression/IRForTarget.cpp +++ b/lldb/source/Expression/IRForTarget.cpp @@ -31,11 +31,13 @@ using namespace llvm; static char ID; IRForTarget::IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map, - const TargetData *target_data) : + const TargetData *target_data, + const char *func_name) : ModulePass(&ID), m_decl_map(decl_map), m_target_data(target_data), - m_sel_registerName(NULL) + m_sel_registerName(NULL), + m_func_name(func_name) { } @@ -910,12 +912,12 @@ IRForTarget::runOnModule(Module &M) { lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - Function* function = M.getFunction(StringRef("___clang_expr")); + Function* function = M.getFunction(StringRef(m_func_name.c_str())); if (!function) { if (log) - log->Printf("Couldn't find ___clang_expr() in the module"); + log->Printf("Couldn't find %s() in the module", m_func_name.c_str()); return false; } diff --git a/lldb/source/Expression/IRToDWARF.cpp b/lldb/source/Expression/IRToDWARF.cpp index 121a47c171e..b158da6c1f5 100644 --- a/lldb/source/Expression/IRToDWARF.cpp +++ b/lldb/source/Expression/IRToDWARF.cpp @@ -26,13 +26,15 @@ using namespace llvm; static char ID; -IRToDWARF::IRToDWARF(lldb_private::ClangExpressionVariableList &variable_list, +IRToDWARF::IRToDWARF(lldb_private::ClangExpressionVariableStore &local_vars, lldb_private::ClangExpressionDeclMap *decl_map, - lldb_private::StreamString &strm) : + lldb_private::StreamString &strm, + const char *func_name) : ModulePass(&ID), - m_variable_list(variable_list), + m_local_vars(local_vars), m_decl_map(decl_map), - m_strm(strm) + m_strm(strm), + m_func_name(func_name) { } @@ -171,14 +173,14 @@ IRToDWARF::runOnModule(Module &M) { lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS); - llvm::Function* function = M.getFunction(StringRef("___clang_expr")); + llvm::Function* function = M.getFunction(StringRef(m_func_name.c_str())); if (!function) { if (log) - log->Printf("Couldn't find ___clang_expr() in the module"); + log->Printf("Couldn't find %s() in the module", m_func_name.c_str()); - return 1; + return false; } Relocator relocator; diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index db5cb65f42e..eaf886f76ad 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -16,7 +16,7 @@ #include "../Commands/CommandObjectApropos.h" #include "../Commands/CommandObjectArgs.h" #include "../Commands/CommandObjectBreakpoint.h" -#include "../Commands/CommandObjectCall.h" +//#include "../Commands/CommandObjectCall.h" #include "../Commands/CommandObjectDelete.h" #include "../Commands/CommandObjectDisassemble.h" #include "../Commands/CommandObjectExpression.h" @@ -207,7 +207,7 @@ CommandInterpreter::LoadCommandDictionary () m_command_dict["append"] = CommandObjectSP (new CommandObjectAppend ()); m_command_dict["apropos"] = CommandObjectSP (new CommandObjectApropos ()); m_command_dict["breakpoint"]= CommandObjectSP (new CommandObjectMultiwordBreakpoint (*this)); - m_command_dict["call"] = CommandObjectSP (new CommandObjectCall ()); + //m_command_dict["call"] = CommandObjectSP (new CommandObjectCall ()); m_command_dict["commands"] = CommandObjectSP (new CommandObjectMultiwordCommands (*this)); m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble ()); m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression ()); |