This is a major refactoring of the expression parser.
The goal is to separate the parser's data from the data
belonging to the parser's clients. This allows clients
to use the parser to obtain (for example) a JIT compiled
function or some DWARF code, and then discard the parser
state.
Previously, parser state was held in ClangExpression and
used liberally by ClangFunction, which inherited from
ClangExpression. The main effects of this refactoring
are:
- reducing ClangExpression to an abstract class that
declares methods that any client must expose to the
expression parser,
- moving the code specific to implementing the "expr"
command from ClangExpression and
CommandObjectExpression into ClangUserExpression,
a new class,
- moving the common parser interaction code from
ClangExpression into ClangExpressionParser, a new
class, and
- making ClangFunction rely only on
ClangExpressionParser and not depend on the
internal implementation of ClangExpression.
Side effects include:
- the compiler interaction code has been factored
out of ClangFunction and is now in an AST pass
(ASTStructExtractor),
- the header file for ClangFunction is now fully
documented,
- several bugs that only popped up when Clang was
deallocated (which never happened, since the
lifetime of the compiler was essentially infinite)
are now fixed, and
- the developer-only "call" command has been
disabled.
I have tested the expr command and the Objective-C
step-into code, which use ClangUserExpression and
ClangFunction, respectively, and verified that they
work. Please let me know if you encounter bugs or
poor documentation.
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@112249 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Expression/ClangResultSynthesizer.cpp b/source/Expression/ASTResultSynthesizer.cpp
similarity index 87%
rename from source/Expression/ClangResultSynthesizer.cpp
rename to source/Expression/ASTResultSynthesizer.cpp
index b3922ee..b3790f2 100644
--- a/source/Expression/ClangResultSynthesizer.cpp
+++ b/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 @@
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 @@
}
void
-ClangResultSynthesizer::TransformTopLevelDecl(Decl* D)
+ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
{
LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D);
@@ -81,7 +81,7 @@
}
void
-ClangResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
+ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
{
DeclGroupRef::iterator decl_iterator;
@@ -99,7 +99,7 @@
}
bool
-ClangResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl)
+ASTResultSynthesizer::SynthesizeResult (FunctionDecl *FunDecl)
{
ASTContext &Ctx(*m_ast_context);
@@ -210,42 +210,42 @@
}
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 @@
}
void
-ClangResultSynthesizer::ForgetSema()
+ASTResultSynthesizer::ForgetSema()
{
m_sema = NULL;
m_action = NULL;
diff --git a/source/Expression/ASTStructExtractor.cpp b/source/Expression/ASTStructExtractor.cpp
new file mode 100644
index 0000000..84a97c8
--- /dev/null
+++ b/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/source/Expression/ClangExpression.cpp b/source/Expression/ClangExpression.cpp
deleted file mode 100644
index 416bd3e..0000000
--- a/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/source/Expression/ClangExpressionParser.cpp b/source/Expression/ClangExpressionParser.cpp
new file mode 100644
index 0000000..05c237a
--- /dev/null
+++ b/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/source/Expression/ClangFunction.cpp b/source/Expression/ClangFunction.cpp
index 5d3e4c8..be107ca 100644
--- a/source/Expression/ClangFunction.cpp
+++ b/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 @@
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 @@
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 @@
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) (");
+ int num_func_args = m_function_ptr->GetArgumentCount();
+ if (num_func_args >= 0)
+ trust_function = true;
+ else
+ num_args = num_func_args;
+ }
- // Get the number of arguments. If we have a function type and it is prototyped,
- // trust that, otherwise use the values we were given.
+ if (num_args == UINT32_MAX)
+ num_args = m_arg_values.GetSize();
- // 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.
+ 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;
- uint32_t num_args = UINT32_MAX;
- bool trust_function = false;
- // GetArgumentCount returns -1 for an unprototyped function.
- if (m_function_ptr)
+ if (trust_function)
{
- int num_func_args = m_function_ptr->GetArgumentCount();
- if (num_func_args >= 0)
- trust_function = true;
- else
- num_args = num_func_args;
+ type_string = m_function_ptr->GetArgumentTypeAtIndex(i).GetName().AsCString();
}
-
- 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++)
+ else
{
- const char *type_string;
- std::string type_stdstr;
-
- if (trust_function)
+ 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;
- }
- }
-
-
- 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();
-
- 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;
-
- FunctionDecl *wrapper_func = dyn_cast<FunctionDecl> (*(func_lookup.first));
- if (!wrapper_func)
- return false;
-
- 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;
-
- RecordDecl *wrapper_struct = dyn_cast<RecordDecl>(*(struct_lookup.first));
-
- if (!wrapper_struct)
- return false;
-
- m_struct_layout = &ast_context.getASTRecordLayout (wrapper_struct);
- if (!m_struct_layout)
- {
- m_compiled = false;
+ {
+ errors.Printf("Could not determine type of input value %d.", i);
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;
}
+
+ m_wrapper_function_text.append (type_string);
+ if (i < num_args - 1)
+ m_wrapper_function_text.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 (", ");
+
}
+ m_wrapper_function_text.append (");\n"); // Close off the function calling prototype.
+
+ m_wrapper_function_text.append (args_buffer);
+
+ 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");
+
+ 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");
+
+ 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 @@
{
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 @@
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 @@
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 @@
// 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 @@
{
// 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 @@
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 @@
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/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp
new file mode 100644
index 0000000..afd94bb
--- /dev/null
+++ b/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/source/Expression/IRForTarget.cpp b/source/Expression/IRForTarget.cpp
index c14891b..d74302c 100644
--- a/source/Expression/IRForTarget.cpp
+++ b/source/Expression/IRForTarget.cpp
@@ -31,11 +31,13 @@
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 @@
{
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/source/Expression/IRToDWARF.cpp b/source/Expression/IRToDWARF.cpp
index 121a47c..b158da6 100644
--- a/source/Expression/IRToDWARF.cpp
+++ b/source/Expression/IRToDWARF.cpp
@@ -26,13 +26,15 @@
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 @@
{
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;