diff options
Diffstat (limited to 'lldb/source/Expression')
-rw-r--r-- | lldb/source/Expression/ClangASTSource.cpp | 101 | ||||
-rw-r--r-- | lldb/source/Expression/ClangExpression.cpp | 633 | ||||
-rw-r--r-- | lldb/source/Expression/ClangExpressionDeclMap.cpp | 246 | ||||
-rw-r--r-- | lldb/source/Expression/ClangExpressionVariable.cpp | 100 | ||||
-rw-r--r-- | lldb/source/Expression/ClangFunction.cpp | 671 | ||||
-rw-r--r-- | lldb/source/Expression/ClangStmtVisitor.cpp | 1032 | ||||
-rw-r--r-- | lldb/source/Expression/DWARFExpression.cpp | 2589 | ||||
-rw-r--r-- | lldb/source/Expression/RecordingMemoryManager.cpp | 131 |
8 files changed, 5503 insertions, 0 deletions
diff --git a/lldb/source/Expression/ClangASTSource.cpp b/lldb/source/Expression/ClangASTSource.cpp new file mode 100644 index 00000000000..996c20529ac --- /dev/null +++ b/lldb/source/Expression/ClangASTSource.cpp @@ -0,0 +1,101 @@ +/* + * ClangASTSource.cpp + * lldb + * + * Created by John McCall on 6/1/10. + * Copyright 2010 Apple. All rights reserved. + * + */ + +#define NO_RTTI + +#include "clang/AST/ASTContext.h" +#include "lldb/Expression/ClangASTSource.h" +#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/ClangExpressionDeclMap.h" + +using namespace clang; +using namespace lldb_private; + +ClangASTSource::~ClangASTSource() {} + +void ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer) { + // Tell Sema to ask us when looking into the translation unit's decl. + Context.getTranslationUnitDecl()->setHasExternalVisibleStorage(); + Context.getTranslationUnitDecl()->setHasExternalLexicalStorage(); +} + +// These are only required for AST source that want to lazily load +// the declarations (or parts thereof) that they return. +Decl *ClangASTSource::GetExternalDecl(uint32_t) { return 0; } +Stmt *ClangASTSource::GetExternalDeclStmt(uint64_t) { return 0; } + +// These are also optional, although it might help with ObjC +// debugging if we have respectable signatures. But a more +// efficient interface (that didn't require scanning all files +// for method signatures!) might help. +Selector ClangASTSource::GetExternalSelector(uint32_t) { return Selector(); } +uint32_t ClangASTSource::GetNumExternalSelectors() { return 0; } + +// The core lookup interface. +DeclContext::lookup_result ClangASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { + switch (Name.getNameKind()) { + // Normal identifiers. + case DeclarationName::Identifier: + break; + + // Operator names. Not important for now. + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + return DeclContext::lookup_result(); + + // Using directives found in this context. + // Tell Sema we didn't find any or we'll end up getting asked a *lot*. + case DeclarationName::CXXUsingDirective: + return SetNoExternalVisibleDeclsForName(DC, Name); + + // These aren't looked up like this. + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return DeclContext::lookup_result(); + + // These aren't possible in the global context. + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + return DeclContext::lookup_result(); + } + + llvm::SmallVector<NamedDecl*, 4> Decls; + + NameSearchContext NSC(*this, Decls, Name, DC); + + DeclMap.GetDecls(NSC, Name.getAsString().c_str()); + return SetExternalVisibleDeclsForName(DC, Name, Decls); +} + +// This is used to support iterating through an entire lexical context, +// which isn't something the debugger should ever need to do. +bool ClangASTSource::FindExternalLexicalDecls(const DeclContext *DC, llvm::SmallVectorImpl<Decl*> &Decls) { + // true is for error, that's good enough for me + return true; +} + +clang::ASTContext *NameSearchContext::GetASTContext() { + return &ASTSource.Context; +} + +clang::NamedDecl *NameSearchContext::AddVarDecl(void *type) { + clang::NamedDecl *Decl = VarDecl::Create(ASTSource.Context, + const_cast<DeclContext*>(DC), + SourceLocation(), + Name.getAsIdentifierInfo(), + QualType::getFromOpaquePtr(type), + 0, + VarDecl::Static, + VarDecl::Static); + Decls.push_back(Decl); + + return Decl; +} diff --git a/lldb/source/Expression/ClangExpression.cpp b/lldb/source/Expression/ClangExpression.cpp new file mode 100644 index 00000000000..f7742c685c7 --- /dev/null +++ b/lldb/source/Expression/ClangExpression.cpp @@ -0,0 +1,633 @@ +//===-- 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/CodeGen/ModuleBuilder.h" +#include "clang/Driver/CC1Options.h" +#include "clang/Driver/OptTable.h" +#include "clang/Frontend/CodeGenAction.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/Sema/ParseAST.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/MemoryBuffer.h" +#include "llvm/System/DynamicLibrary.h" +#include "llvm/System/Host.h" +#include "llvm/System/Signals.h" +#include "llvm/Target/TargetSelect.h" + +// Project includes +#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/ClangASTSource.h" +#include "lldb/Expression/ClangStmtVisitor.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Expression/RecordingMemoryManager.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" + +#define NO_RTTI +#include "lldb/Core/StreamString.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Core/dwarf.h" + + +using namespace lldb_private; +using namespace clang; +using namespace llvm; + +namespace clang { + +class AnalyzerOptions; +class CodeGenOptions; +class DependencyOutputOptions; +class DiagnosticOptions; +class FrontendOptions; +class HeaderSearchOptions; +class LangOptions; +class PreprocessorOptions; +class PreprocessorOutputOptions; +class TargetInfo; +class TargetOptions; + +} // end namespace clang + + + +//===----------------------------------------------------------------------===// +// 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 +//===----------------------------------------------------------------------===// + +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 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 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 ParseNoop: return new ParseOnlyAction(); + case ParsePrintCallbacks: return new PrintParseAction(); + case ParseSyntaxOnly: return new SyntaxOnlyAction(); + + case PluginAction: { + if (CI.getFrontendOpts().ActionName == "help") { + llvm::errs() << "clang -cc1 plugins:\n"; + for (FrontendPluginRegistry::iterator it = + FrontendPluginRegistry::begin(), + ie = FrontendPluginRegistry::end(); + it != ie; ++it) + llvm::errs() << " " << it->getName() << " - " << it->getDesc() << "\n"; + return 0; + } + + for (FrontendPluginRegistry::iterator it = + FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); + it != ie; ++it) { + if (it->getName() == CI.getFrontendOpts().ActionName) + return it->instantiate(); + } + + CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) + << CI.getFrontendOpts().ActionName; + return 0; + } + + case PrintDeclContext: return new DeclContextPrintAction(); + 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(); + } +} + +//---------------------------------------------------------------------- +// ClangExpression constructor +//---------------------------------------------------------------------- +ClangExpression::ClangExpression(const char *target_triple, + ClangExpressionDeclMap *decl_map) : + m_target_triple (), + m_jit_mm_ptr (NULL), + m_code_generator_ptr (NULL), + m_decl_map (decl_map) +{ + 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 (bool &IsAST) +{ + // 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; + + // 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); + m_clang_ap->getLangOpts().CPlusPlus = true; + + // 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) +{ + // 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("void ___clang_expr()\n{\n\t"); + func_expr.append(expr_text); + func_expr.append(";\n}"); + return ParseBareExpression (func_expr, stream); + +} + +unsigned +ClangExpression::ParseBareExpression (llvm::StringRef expr_text, Stream &stream) +{ + Mutex::Locker locker(GetClangMutex ()); + + TextDiagnosticBuffer text_diagnostic_buffer; + + bool IsAST = false; + if (!CreateCompilerInstance (IsAST)) + { + 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()); + + 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. + 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; +} + + +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; +} + + +unsigned +ClangExpression::ConvertExpressionToDWARF (ClangExpressionVariableList& expr_local_variable_list, + StreamString &dwarf_opcode_strm) +{ + CompilerInstance *compiler_instance = GetCompilerInstance(); + + DeclarationName hack_func_name(&compiler_instance->getASTContext().Idents.get("___clang_expr")); + DeclContext::lookup_result result = compiler_instance->getASTContext().getTranslationUnitDecl()->lookup(hack_func_name); + + if (result.first != result.second) + { + Decl *decl = *result.first; + Stmt *decl_stmt = decl->getBody(); + if (decl_stmt) + { + ClangStmtVisitor visitor(compiler_instance->getASTContext(), expr_local_variable_list, m_decl_map, dwarf_opcode_strm); + + visitor.Visit (decl_stmt); + } + } + return 0; +} + +bool +ClangExpression::JITFunction (const ExecutionContext &exc_context, const char *name) +{ + + 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 (m_execution_engine.get() == 0) + m_execution_engine.reset(llvm::ExecutionEngine::createJIT (module, &error, m_jit_mm_ptr)); + 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) +{ + 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 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++) + { + size += (*fun_pos).second - (*fun_pos).first; + } + + Error error; + lldb::addr_t target_addr = exc_context.process->AllocateMemory (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++) + { + 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; +} + +unsigned +ClangExpression::Compile() +{ + Mutex::Locker locker(GetClangMutex ()); + bool IsAST = false; + + if (CreateCompilerInstance(IsAST)) + { + // Validate/process some options + if (m_clang_ap->getHeaderSearchOpts().Verbose) + llvm::errs() << "clang-cc version " CLANG_VERSION_STRING + << " based upon " << PACKAGE_STRING + << " hosted on " << llvm::sys::getHostTriple() << "\n"; + + // Enforce certain implications. + if (!m_clang_ap->getFrontendOpts().ViewClassInheritance.empty()) + m_clang_ap->getFrontendOpts().ProgramAction = frontend::InheritanceView; +// if (!compiler_instance->getFrontendOpts().FixItSuffix.empty()) +// compiler_instance->getFrontendOpts().ProgramAction = frontend::FixIt; + + for (unsigned i = 0, e = m_clang_ap->getFrontendOpts().Inputs.size(); i != e; ++i) { + const std::string &InFile = m_clang_ap->getFrontendOpts().Inputs[i].second; + + // If we aren't using an AST file, setup the file and source managers and + // the preprocessor. + if (!IsAST) { + if (!i) { + // Create a file manager object to provide access to and cache the + // filesystem. + m_clang_ap->createFileManager(); + + // Create the source manager. + m_clang_ap->createSourceManager(); + } else { + // Reset the ID tables if we are reusing the SourceManager. + m_clang_ap->getSourceManager().clearIDTables(); + } + + // Create the preprocessor. + m_clang_ap->createPreprocessor(); + } + + llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(*m_clang_ap.get())); + if (!Act) + break; + + if (Act->BeginSourceFile(*m_clang_ap, InFile, IsAST)) { + Act->Execute(); + Act->EndSourceFile(); + } + } + + if (m_clang_ap->getDiagnosticOpts().ShowCarets) + { + unsigned NumWarnings = m_clang_ap->getDiagnostics().getNumWarnings(); + unsigned NumErrors = m_clang_ap->getDiagnostics().getNumErrors() - + m_clang_ap->getDiagnostics().getNumErrorsSuppressed(); + + if (NumWarnings || NumErrors) + { + if (NumWarnings) + fprintf (stderr, "%u warning%s%s", NumWarnings, (NumWarnings == 1 ? "" : "s"), (NumErrors ? " and " : "")); + if (NumErrors) + fprintf (stderr, "%u error%s", NumErrors, (NumErrors == 1 ? "" : "s")); + fprintf (stderr, " generated.\n"); + } + } + + if (m_clang_ap->getFrontendOpts().ShowStats) { + m_clang_ap->getFileManager().PrintStats(); + fprintf(stderr, "\n"); + } + + // Return the appropriate status when verifying diagnostics. + // + // FIXME: If we could make getNumErrors() do the right thing, we wouldn't need + // this. + if (m_clang_ap->getDiagnosticOpts().VerifyDiagnostics) + return static_cast<VerifyDiagnosticsClient&>(m_clang_ap->getDiagnosticClient()).HadErrors(); + + return m_clang_ap->getDiagnostics().getNumErrors(); + } + return 1; +} diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp new file mode 100644 index 00000000000..1065211e45b --- /dev/null +++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp @@ -0,0 +1,246 @@ +//===-- ClangExpressionDeclMap.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/ClangExpressionDeclMap.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/Module.h" +#include "lldb/Expression/ClangASTSource.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/TypeList.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/ExecutionContext.h" + +//#define DEBUG_CEDM +#ifdef DEBUG_CEDM +#define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__) +#else +#define DEBUG_PRINTF(...) +#endif + +using namespace lldb_private; +using namespace clang; + +ClangExpressionDeclMap::ClangExpressionDeclMap(ExecutionContext *exe_ctx) : + m_exe_ctx(exe_ctx) +{ + if (exe_ctx && exe_ctx->frame) + m_sym_ctx = new SymbolContext(exe_ctx->frame->GetSymbolContext(lldb::eSymbolContextEverything)); + else + m_sym_ctx = NULL; +} + +ClangExpressionDeclMap::~ClangExpressionDeclMap() +{ + uint32_t num_tuples = m_tuples.size (); + uint32_t tuple_index; + + for (tuple_index = 0; tuple_index < num_tuples; ++tuple_index) + delete m_tuples[tuple_index].m_value; + + if (m_sym_ctx) + delete m_sym_ctx; +} + +bool +ClangExpressionDeclMap::GetIndexForDecl (uint32_t &index, + const clang::Decl *decl) +{ + uint32_t num_tuples = m_tuples.size (); + uint32_t tuple_index; + + for (tuple_index = 0; tuple_index < num_tuples; ++tuple_index) + { + if (m_tuples[tuple_index].m_decl == decl) + { + index = tuple_index; + return true; + } + } + + return false; +} + +// Interface for DwarfExpression +Value +*ClangExpressionDeclMap::GetValueForIndex (uint32_t index) +{ + if (index >= m_tuples.size ()) + return NULL; + + return m_tuples[index].m_value; +} + +// Interface for ClangASTSource +void +ClangExpressionDeclMap::GetDecls(NameSearchContext &context, + const char *name) +{ + DEBUG_PRINTF("Hunting for a definition for %s\n", name); + + // Back out in all cases where we're not fully initialized + if (!m_exe_ctx || !m_exe_ctx->frame || !m_sym_ctx) + return; + + Function *function = m_sym_ctx->function; + Block *block = m_sym_ctx->block; + + if (!function || !block) + { + DEBUG_PRINTF("function = %p, block = %p\n", function, block); + return; + } + + BlockList& blocks = function->GetBlocks(true); + + lldb::user_id_t current_block_id = block->GetID(); + + ConstString name_cs(name); + + for (current_block_id = block->GetID(); + current_block_id != Block::InvalidID; + current_block_id = blocks.GetParent(current_block_id)) + { + Block *current_block = blocks.GetBlockByID(current_block_id); + + lldb::VariableListSP var_list = current_block->GetVariableList(false, true); + + if (!var_list) + continue; + + lldb::VariableSP var = var_list->FindVariable(name_cs); + + if (!var) + continue; + + AddOneVariable(context, var.get()); + return; + } + + { + CompileUnit *compile_unit = m_sym_ctx->comp_unit; + + if (!compile_unit) + { + DEBUG_PRINTF("compile_unit = %p\n", compile_unit); + return; + } + + lldb::VariableListSP var_list = compile_unit->GetVariableList(true); + + if (!var_list) + return; + + lldb::VariableSP var = var_list->FindVariable(name_cs); + + if (!var) + return; + + AddOneVariable(context, var.get()); + return; + } +} + +void +ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, + Variable* var) +{ + Type *var_type = var->GetType(); + + if (!var_type) + { + DEBUG_PRINTF("Skipped a definition for %s because it has no type\n", name); + return; + } + + void *var_opaque_type = var_type->GetOpaqueClangQualType(); + + if (!var_opaque_type) + { + DEBUG_PRINTF("Skipped a definition for %s because it has no Clang type\n", name); + return; + } + + DWARFExpression &var_location_expr = var->LocationExpression(); + + TypeList *type_list = var_type->GetTypeList(); + + if (!type_list) + { + DEBUG_PRINTF("Skipped a definition for %s because the type has no associated type list\n", name); + return; + } + + clang::ASTContext *exe_ast_ctx = type_list->GetClangASTContext().getASTContext(); + + if (!exe_ast_ctx) + { + DEBUG_PRINTF("There is no AST context for the current execution context\n"); + return; + } + + std::auto_ptr<Value> var_location(new Value); + + Error err; + + if (!var_location_expr.Evaluate(m_exe_ctx, exe_ast_ctx, NULL, *var_location.get(), &err)) + { + DEBUG_PRINTF("Error evaluating the location of %s: %s\n", name, err.AsCString()); + return; + } + + void *copied_type = ClangASTContext::CopyType(context.GetASTContext(), type_list->GetClangASTContext().getASTContext(), var_opaque_type); + + if (var_location.get()->GetContextType() == Value::eContextTypeInvalid) + var_location.get()->SetContext(Value::eContextTypeOpaqueClangQualType, copied_type); + + if (var_location.get()->GetValueType() == Value::eValueTypeFileAddress) + { + SymbolContext var_sc; + var->CalculateSymbolContext(&var_sc); + + if (!var_sc.module_sp) + return; + + ObjectFile *object_file = var_sc.module_sp->GetObjectFile(); + + if (!object_file) + return; + + Address so_addr(var_location->GetScalar().ULongLong(), object_file->GetSectionList()); + + lldb::addr_t load_addr = so_addr.GetLoadAddress(m_exe_ctx->process); + + var_location->GetScalar() = load_addr; + var_location->SetValueType(Value::eValueTypeLoadAddress); + } + + NamedDecl *var_decl = context.AddVarDecl(copied_type); + + Tuple tuple; + + tuple.m_decl = var_decl; + tuple.m_value = var_location.release(); + + m_tuples.push_back(tuple); + + DEBUG_PRINTF("Found for a definition for %s\n", name); +} diff --git a/lldb/source/Expression/ClangExpressionVariable.cpp b/lldb/source/Expression/ClangExpressionVariable.cpp new file mode 100644 index 00000000000..40fee4b47f5 --- /dev/null +++ b/lldb/source/Expression/ClangExpressionVariable.cpp @@ -0,0 +1,100 @@ +//===-- ClangExpressionVariable.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/ClangExpressionVariable.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "clang/AST/ASTContext.h" + +using namespace lldb_private; +using namespace clang; + +ClangExpressionVariableList::ClangExpressionVariableList() : + m_variables() +{ +} + +ClangExpressionVariableList::~ClangExpressionVariableList() +{ + uint32_t num_variables = m_variables.size(); + uint32_t var_index; + + for (var_index = 0; var_index < num_variables; ++var_index) + delete m_variables[var_index].m_value; +} + +Value * +ValueForDecl(ASTContext &ast_context, const VarDecl *var_decl) +{ + Value *ret = new Value; + + ret->SetContext(Value::eContextTypeOpaqueClangQualType, + var_decl->getType().getAsOpaquePtr()); + + uint64_t bit_width = ast_context.getTypeSize(var_decl->getType()); + + uint32_t byte_size = (bit_width + 7 ) / 8; + + ret->ResizeData(byte_size); + + return ret; +} + +Value * +ClangExpressionVariableList::GetVariableForVarDecl (ASTContext &ast_context, const VarDecl *var_decl, uint32_t& idx, bool can_create) +{ + uint32_t num_variables = m_variables.size(); + uint32_t var_index; + + for (var_index = 0; var_index < num_variables; ++var_index) + { + if (m_variables[var_index].m_var_decl == var_decl) + { + idx = var_index; + return m_variables[var_index].m_value; + } + } + + if (!can_create) + return NULL; + + idx = m_variables.size(); + + ClangExpressionVariable val; + val.m_var_decl = var_decl; + val.m_value = ValueForDecl(ast_context, var_decl); + m_variables.push_back(val); + + return m_variables.back().m_value; +} + +Value * +ClangExpressionVariableList::GetVariableAtIndex (uint32_t idx) +{ + if (idx < m_variables.size()) + return m_variables[idx].m_value; + + return NULL; +} + +uint32_t +ClangExpressionVariableList::AppendValue (Value *value) +{ + uint32_t idx = m_variables.size(); + + ClangExpressionVariable val; + val.m_var_decl = NULL; + val.m_value = value; + + m_variables.push_back(val); + return idx; +} diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp new file mode 100644 index 00000000000..e8713d0fd49 --- /dev/null +++ b/lldb/source/Expression/ClangFunction.cpp @@ -0,0 +1,671 @@ +//===-- ClangFunction.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 +// C++ Includes +// Other libraries and framework includes +#include "clang/Frontend/CodeGenAction.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" +#include "llvm/ExecutionEngine/JIT.h" +#include "llvm/Module.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "llvm/ADT/StringRef.h" + +// Project includes +#include "lldb/Expression/ClangFunction.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectList.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallFunction.h" +#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_function_addr (functionAddress), + m_function_ptr (NULL), + m_arg_values (arg_value_list), + m_clang_ast_context (ast_context), + m_function_return_qual_type(return_qualtype), + m_wrapper_function_name ("__lldb_caller_function"), + m_wrapper_struct_name ("__lldb_caller_struct"), + m_return_offset(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_function_ptr (&function), + m_arg_values (arg_value_list), + m_clang_ast_context (ast_context), + m_function_return_qual_type (NULL), + m_wrapper_function_name ("__lldb_function_caller"), + m_wrapper_struct_name ("__lldb_caller_struct"), + m_return_offset(0), + m_compiled (false), + m_JITted (false) +{ + m_function_addr = m_function_ptr->GetAddressRange().GetBaseAddress(); + m_function_return_qual_type = m_function_ptr->GetReturnType().GetOpaqueClangQualType(); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +ClangFunction::~ClangFunction() +{ +} + +unsigned +ClangFunction::CompileFunction (Stream &errors) +{ + // 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... + 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. + + size_t num_args = -1; + bool trust_function = false; + // GetArgumentCount returns -1 for an unprototyped function. + if (m_function_ptr) + { + num_args = m_function_ptr->GetArgumentCount(); + if (num_args != -1) + trust_function = true; + } + + if (num_args == -1) + 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 (int i = 0; i < num_args; i++) + { + const char *type_string; + std::string type_stdstr; + + 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_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_%d", 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; + 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; + } + } + + return num_errors; +} + +bool +ClangFunction::WriteFunctionWrapper (ExecutionContext &exc_context, Stream &errors) +{ + Process *process = exc_context.process; + + if (process == NULL) + return false; + + if (!m_JITted) + { + // Next we should JIT it and insert the result into the target program. + if (!JITFunction (exc_context, m_wrapper_function_name.c_str())) + return false; + + if (!WriteJITCode (exc_context)) + return false; + + m_JITted = true; + } + + // Next get the call address for the function: + m_wrapper_fun_addr = GetFunctionAddress (m_wrapper_function_name.c_str()); + if (m_wrapper_fun_addr == LLDB_INVALID_ADDRESS) + return false; + + return true; +} + +bool +ClangFunction::WriteFunctionArguments (ExecutionContext &exc_context, lldb::addr_t &args_addr_ref, Stream &errors) +{ + return WriteFunctionArguments(exc_context, args_addr_ref, m_function_addr, m_arg_values, errors); +} + +// FIXME: Assure that the ValueList we were passed in is consistent with the one that defined this function. + +bool +ClangFunction::WriteFunctionArguments (ExecutionContext &exc_context, 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. + + Error error; + using namespace clang; + ExecutionResults return_value = eExecutionSetupError; + + Process *process = exc_context.process; + + 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); + if (args_addr_ref == LLDB_INVALID_ADDRESS) + return false; + m_wrapper_args_addrs.push_back (args_addr_ref); + } + else + { + // Make sure this is an address that we've already handed out. + if (find (m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), args_addr_ref) == m_wrapper_args_addrs.end()) + { + return false; + } + } + + // FIXME: This is fake, and just assumes that it matches that architecture. + // Make a data extractor and put the address into the right byte order & size. + + uint64_t fun_addr = function_address.GetLoadAddress(exc_context.process); + int first_offset = m_struct_layout->getFieldOffset(0)/8; + process->WriteMemory(args_addr_ref + first_offset, &fun_addr, 8, error); + + // FIXME: We will need to extend this for Variadic functions. + + Error value_error; + + size_t num_args = arg_values.GetSize(); + if (num_args != m_arg_values.GetSize()) + { + errors.Printf ("Wrong number of arguments - was: %d should be: %d", num_args, m_arg_values.GetSize()); + return false; + } + + for (int i = 0; i < num_args; i++) + { + // FIXME: We should sanity check sizes. + + int offset = m_struct_layout->getFieldOffset(i+1)/8; // Clang sizes are in bytes. + Value *arg_value = arg_values.GetValueAtIndex(i); + + // FIXME: For now just do scalars: + + // Special case: if it's a pointer, don't do anything (the ABI supports passing cstrings) + + if (arg_value->GetValueType() == Value::eValueTypeHostAddress && + arg_value->GetContextType() == Value::eContextTypeOpaqueClangQualType && + ClangASTContext::IsPointerType(arg_value->GetValueOpaqueClangQualType())) + continue; + + const Scalar &arg_scalar = arg_value->ResolveValue(&exc_context, m_clang_ast_context->getASTContext()); + + int byte_size = arg_scalar.GetByteSize(); + std::vector<uint8_t> buffer; + buffer.resize(byte_size); + DataExtractor value_data; + arg_scalar.GetData (value_data); + value_data.ExtractBytes(0, byte_size, process->GetByteOrder(), buffer.data()); + process->WriteMemory(args_addr_ref + offset, buffer.data(), byte_size, error); + } + + return true; +} + +bool +ClangFunction::InsertFunction (ExecutionContext &exc_context, lldb::addr_t &args_addr_ref, Stream &errors) +{ + using namespace clang; + + if (CompileFunction(errors) != 0) + return false; + if (!WriteFunctionWrapper(exc_context, errors)) + return false; + if (!WriteFunctionArguments(exc_context, args_addr_ref, errors)) + return false; + + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); + if (log) + log->Printf ("Call Address: 0x%llx Struct Address: 0x%llx.\n", m_wrapper_fun_addr, args_addr_ref); + + return true; +} + +ThreadPlan * +ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exc_context, lldb::addr_t &args_addr, Stream &errors, bool stop_others, bool discard_on_error) +{ + // FIXME: Use the errors Stream for better error reporting. + + Process *process = exc_context.process; + + if (process == NULL) + { + errors.Printf("Can't call a function without a process."); + return NULL; + } + + // Okay, now run the function: + + Address wrapper_address (NULL, m_wrapper_fun_addr); + ThreadPlan *new_plan = new ThreadPlanCallFunction (*exc_context.thread, + wrapper_address, + args_addr, + stop_others, discard_on_error); + return new_plan; +} + +bool +ClangFunction::FetchFunctionResults (ExecutionContext &exc_context, lldb::addr_t args_addr, Value &ret_value) +{ + // Read the return value - it is the last field in the struct: + // FIXME: How does clang tell us there's no return value? We need to handle that case. + + std::vector<uint8_t> data_buffer; + data_buffer.resize(m_return_size); + Process *process = exc_context.process; + Error error; + size_t bytes_read = process->ReadMemory(args_addr + m_return_offset/8, data_buffer.data(), m_return_size, error); + + if (bytes_read == 0) + { + return false; + } + + if (bytes_read < m_return_size) + return false; + + DataExtractor data(data_buffer.data(), m_return_size, process->GetByteOrder(), process->GetAddressByteSize()); + // FIXME: Assuming an integer scalar for now: + + uint32_t offset = 0; + uint64_t return_integer = data.GetMaxU64(&offset, m_return_size); + + ret_value.SetContext (Value::eContextTypeOpaqueClangQualType, m_function_return_qual_type); + ret_value.SetValueType(Value::eValueTypeScalar); + ret_value.GetScalar() = return_integer; + return true; +} + +void +ClangFunction::DeallocateFunctionResults (ExecutionContext &exc_context, lldb::addr_t args_addr) +{ + std::list<lldb::addr_t>::iterator pos; + pos = std::find(m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), args_addr); + if (pos != m_wrapper_args_addrs.end()) + m_wrapper_args_addrs.erase(pos); + + exc_context.process->DeallocateMemory(args_addr); +} + +ClangFunction::ExecutionResults +ClangFunction::ExecuteFunction(ExecutionContext &exc_context, Stream &errors, Value &results) +{ + return ExecuteFunction (exc_context, errors, 1000, true, results); +} + +ClangFunction::ExecutionResults +ClangFunction::ExecuteFunction(ExecutionContext &exc_context, Stream &errors, bool stop_others, Value &results) +{ + return ExecuteFunction (exc_context, NULL, errors, stop_others, NULL, false, results); +} + +ClangFunction::ExecutionResults +ClangFunction::ExecuteFunction( + ExecutionContext &exc_context, + Stream &errors, + uint32_t single_thread_timeout_usec, + bool try_all_threads, + Value &results) +{ + return ExecuteFunction (exc_context, NULL, errors, true, single_thread_timeout_usec, try_all_threads, results); +} + +ClangFunction::ExecutionResults +ClangFunction::ExecuteFunction( + ExecutionContext &exc_context, + lldb::addr_t *args_addr_ptr, + Stream &errors, + bool stop_others, + uint32_t single_thread_timeout_usec, + bool try_all_threads, + Value &results) +{ + using namespace clang; + ExecutionResults return_value = eExecutionSetupError; + Process *process = exc_context.process; + + lldb::addr_t args_addr; + + if (args_addr_ptr != NULL) + args_addr = *args_addr_ptr; + else + args_addr = LLDB_INVALID_ADDRESS; + + if (CompileFunction(errors) != 0) + return eExecutionSetupError; + + if (args_addr == LLDB_INVALID_ADDRESS) + { + if (!InsertFunction(exc_context, args_addr, errors)) + return eExecutionSetupError; + } + + + lldb::ThreadPlanSP call_plan_sp(GetThreadPlanToCallFunction(exc_context, args_addr, errors, stop_others, false)); + + ThreadPlanCallFunction *call_plan_ptr = static_cast<ThreadPlanCallFunction *> (call_plan_sp.get()); + + if (args_addr_ptr != NULL) + *args_addr_ptr = args_addr; + + if (call_plan_sp == NULL) + return return_value; + + call_plan_sp->SetPrivate(true); + exc_context.thread->QueueThreadPlan(call_plan_sp, 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. + + TimeValue* timeout_ptr = NULL; + TimeValue real_timeout; + if (single_thread_timeout_usec != 0) + { + real_timeout = TimeValue::Now(); + real_timeout.OffsetWithMicroSeconds(single_thread_timeout_usec); + timeout_ptr = &real_timeout; + } + 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 (timeout_ptr, event_sp); + if (stop_state == lldb::eStateInvalid && timeout_ptr != NULL) + { + // Right now this is the only way to tell we've timed out... + // We should interrupt the process here... + // Not really sure what to do if Halt fails here... + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); + if (log) + log->Printf ("Running function with timeout: %d timed out, trying with all threads enabled.", single_thread_timeout_usec); + + if (process->Halt().Success()) + { + timeout_ptr = NULL; + + lldb::StateType stop_state = process->WaitForStateChangedEvents (timeout_ptr, event_sp); + if (stop_state == lldb::eStateInvalid) + { + errors.Printf ("Got an invalid stop state after halt."); + } + else if (stop_state != lldb::eStateStopped) + { + StreamString s; + event_sp->Dump (&s); + + errors.Printf("Didn't get a stopped event after Halting the target, got: \"%s\"", s.GetData()); + } + + if (try_all_threads) + { + // Between the time that we got the timeout and the time we halted, but target + // might have actually completed the plan. If so, we're done. + if (exc_context.thread->IsThreadPlanDone (call_plan_sp.get())) + { + return_value = eExecutionCompleted; + break; + } + + + call_plan_ptr->SetStopOthers (false); + process->Resume(); + continue; + } + else + return eExecutionInterrupted; + } + } + if (stop_state == lldb::eStateRunning || stop_state == lldb::eStateStepping) + continue; + + if (exc_context.thread->IsThreadPlanDone (call_plan_sp.get())) + { + return_value = eExecutionCompleted; + break; + } + else if (exc_context.thread->WasThreadPlanDiscarded (call_plan_sp.get())) + { + return_value = eExecutionDiscarded; + break; + } + else + { + return_value = eExecutionInterrupted; + break; + } + + } + + if (return_value != eExecutionCompleted) + return return_value; + + FetchFunctionResults(exc_context, args_addr, results); + + if (args_addr_ptr == NULL) + DeallocateFunctionResults(exc_context, args_addr); + + return eExecutionCompleted; +} + +ClangFunction::ExecutionResults +ClangFunction::ExecuteFunctionWithABI(ExecutionContext &exc_context, Stream &errors, Value &results) +{ + // FIXME: Use the errors Stream for better error reporting. + using namespace clang; + ExecutionResults return_value = eExecutionSetupError; + + Process *process = exc_context.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(&exc_context, GetASTContext()); + + ThreadPlan *call_plan = exc_context.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 (exc_context.thread->IsThreadPlanDone (call_plan)) + { + return_value = eExecutionCompleted; + break; + } + else if (exc_context.thread->WasThreadPlanDiscarded (call_plan)) + { + return_value = eExecutionDiscarded; + break; + } + else + { + return_value = eExecutionInterrupted; + break; + } + + } + + return eExecutionCompleted; +} diff --git a/lldb/source/Expression/ClangStmtVisitor.cpp b/lldb/source/Expression/ClangStmtVisitor.cpp new file mode 100644 index 00000000000..1d2f53fcb80 --- /dev/null +++ b/lldb/source/Expression/ClangStmtVisitor.cpp @@ -0,0 +1,1032 @@ +//===-- ClangStmtVisitor.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/ClangStmtVisitor.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "clang/AST/RecordLayout.h" + +#define NO_RTTI +#include "lldb/Core/dwarf.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Expression/ClangExpressionDeclMap.h" +#include "lldb/Expression/ClangExpressionVariable.h" + +//#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN +#ifdef ENABLE_DEBUG_PRINTF +#include <stdio.h> +#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define DEBUG_PRINTF(fmt, ...) +#endif + +// Project includes + +static lldb_private::Scalar::Type +GetScalarTypeForClangType (clang::ASTContext &ast_context, clang::QualType clang_type, uint32_t &count) +{ + count = 1; + + switch (clang_type->getTypeClass()) + { + case clang::Type::FunctionNoProto: + case clang::Type::FunctionProto: + break; + + case clang::Type::IncompleteArray: + case clang::Type::VariableArray: + break; + + case clang::Type::ConstantArray: + break; + + case clang::Type::ExtVector: + case clang::Type::Vector: + // TODO: Set this to more than one??? + break; + + case clang::Type::Builtin: + switch (cast<clang::BuiltinType>(clang_type)->getKind()) + { + default: assert(0 && "Unknown builtin type!"); + case clang::BuiltinType::Void: + break; + + case clang::BuiltinType::Bool: + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + case clang::BuiltinType::WChar: + case clang::BuiltinType::Char16: + case clang::BuiltinType::Char32: + case clang::BuiltinType::Short: + case clang::BuiltinType::Int: + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::Int128: + return lldb_private::Scalar::GetValueTypeForSignedIntegerWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT)/count); + + case clang::BuiltinType::Char_U: + case clang::BuiltinType::UChar: + case clang::BuiltinType::UShort: + case clang::BuiltinType::UInt: + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + case clang::BuiltinType::UInt128: + case clang::BuiltinType::NullPtr: + return lldb_private::Scalar::GetValueTypeForUnsignedIntegerWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT)/count); + + case clang::BuiltinType::Float: + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + return lldb_private::Scalar::GetValueTypeForFloatWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT)/count); + } + break; + // All pointer types are represented as unsigned integer encodings. + // We may nee to add a eEncodingPointer if we ever need to know the + // difference + case clang::Type::ObjCObjectPointer: + case clang::Type::BlockPointer: + case clang::Type::Pointer: + case clang::Type::LValueReference: + case clang::Type::RValueReference: + case clang::Type::MemberPointer: + return lldb_private::Scalar::GetValueTypeForUnsignedIntegerWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT)/count); + + // Complex numbers are made up of floats + case clang::Type::Complex: + count = 2; + return lldb_private::Scalar::GetValueTypeForFloatWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT) / count); + + case clang::Type::ObjCInterface: break; + case clang::Type::Record: break; + case clang::Type::Enum: + return lldb_private::Scalar::GetValueTypeForSignedIntegerWithByteSize ((ast_context.getTypeSize(clang_type)/CHAR_BIT)/count); + + case clang::Type::Typedef: + return GetScalarTypeForClangType(ast_context, cast<clang::TypedefType>(clang_type)->LookThroughTypedefs(), count); + break; + + case clang::Type::TypeOfExpr: + case clang::Type::TypeOf: + case clang::Type::Decltype: + //case clang::Type::QualifiedName: + case clang::Type::TemplateSpecialization: break; + } + count = 0; + return lldb_private::Scalar::e_void; +} + +//---------------------------------------------------------------------- +// ClangStmtVisitor constructor +//---------------------------------------------------------------------- +lldb_private::ClangStmtVisitor::ClangStmtVisitor +( + clang::ASTContext &ast_context, + lldb_private::ClangExpressionVariableList &variable_list, + lldb_private::ClangExpressionDeclMap *decl_map, + lldb_private::StreamString &strm +) : + m_ast_context (ast_context), + m_variable_list (variable_list), + m_decl_map (decl_map), + m_stream (strm) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +lldb_private::ClangStmtVisitor::~ClangStmtVisitor() +{ +} + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitStmt (clang::Stmt *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + + clang::Stmt::child_iterator pos; + clang::Stmt::child_iterator begin = Node->child_begin(); + clang::Stmt::child_iterator end = Node->child_end(); + bool clear_before_next_stmt = false; + for (pos = begin; pos != end; ++pos) + { +#ifdef ENABLE_DEBUG_PRINTF + pos->dump(); +#endif + clang::Stmt *child_stmt = *pos; + uint32_t pre_visit_stream_offset = m_stream.GetSize(); + bool not_null_stmt = dyn_cast<clang::NullStmt>(child_stmt) == NULL; + if (clear_before_next_stmt && not_null_stmt) + m_stream.PutHex8(DW_OP_APPLE_clear); + Visit (child_stmt); + if (not_null_stmt) + clear_before_next_stmt = pre_visit_stream_offset != m_stream.GetSize(); + } +} + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitDeclStmt (clang::DeclStmt *decl_stmt) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + clang::DeclGroupRef decl_group_ref = decl_stmt->getDeclGroup(); + clang::DeclGroupRef::iterator pos, end = decl_group_ref.end(); + for (pos = decl_group_ref.begin(); pos != end; ++pos) + { + clang::Decl *decl = *pos; + if (decl) + { + clang::Decl::Kind decl_kind = decl->getKind(); + + switch (decl_kind) + { + case clang::Decl::Namespace: + case clang::Decl::Enum: + case clang::Decl::Record: + case clang::Decl::CXXRecord: + case clang::Decl::ObjCMethod: + case clang::Decl::ObjCInterface: + case clang::Decl::ObjCCategory: + case clang::Decl::ObjCProtocol: + case clang::Decl::ObjCImplementation: + case clang::Decl::ObjCCategoryImpl: + case clang::Decl::LinkageSpec: + case clang::Decl::Block: + case clang::Decl::Function: + case clang::Decl::CXXMethod: + case clang::Decl::CXXConstructor: + case clang::Decl::CXXDestructor: + case clang::Decl::CXXConversion: + case clang::Decl::Field: + case clang::Decl::Typedef: + case clang::Decl::EnumConstant: + case clang::Decl::ImplicitParam: + case clang::Decl::ParmVar: + case clang::Decl::ObjCProperty: + break; + + case clang::Decl::Var: + { + const clang::VarDecl *var_decl = cast<clang::VarDecl>(decl)->getCanonicalDecl(); + uint32_t expr_local_var_idx = UINT32_MAX; + if (m_variable_list.GetVariableForVarDecl (m_ast_context, var_decl, expr_local_var_idx, true)) + { + const clang::Expr* var_decl_expr = var_decl->getAnyInitializer(); + // If there is an inialization expression, then assign the + // variable. + if (var_decl_expr) + { + m_stream.PutHex8(DW_OP_APPLE_expr_local); + m_stream.PutULEB128(expr_local_var_idx); + Visit ((clang::Stmt *)var_decl_expr); + m_stream.PutHex8(DW_OP_APPLE_assign); + } + } + } + break; + + default: + assert(!"decl unhandled"); + break; + } + } + } +} + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitLabelStmt (clang::LabelStmt *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitGotoStmt (clang::GotoStmt *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +// Exprs +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitExpr (clang::Expr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitDeclRefExpr (clang::DeclRefExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + clang::NamedDecl *decl = Node->getDecl(); + clang::QualType clang_type = Node->getType(); + +#ifdef ENABLE_DEBUG_PRINTF + //decl->dump(); + //clang_type.dump("lldb_private::ClangStmtVisitor::VisitDeclRefExpr() -> clang_type.dump() = "); +#endif + uint32_t expr_local_var_idx = UINT32_MAX; + if (m_variable_list.GetVariableForVarDecl (m_ast_context, cast<clang::VarDecl>(decl)->getCanonicalDecl(), expr_local_var_idx, false) && + expr_local_var_idx != UINT32_MAX) + { + m_stream.PutHex8(DW_OP_APPLE_expr_local); + m_stream.PutULEB128(expr_local_var_idx); + } + else if (m_decl_map && + m_decl_map->GetIndexForDecl(expr_local_var_idx, decl->getCanonicalDecl())) + { + m_stream.PutHex8(DW_OP_APPLE_extern); + m_stream.PutULEB128(expr_local_var_idx); + } + else + { + m_stream.PutHex8 (DW_OP_APPLE_error); + } +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitPredefinedExpr (clang::PredefinedExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitCharacterLiteral (clang::CharacterLiteral *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + clang::QualType clang_type = Node->getType(); + uint64_t clang_type_size = m_ast_context.getTypeSize (clang_type); + if (clang_type_size <= 64) + { + // Encode the integer into our DWARF expression + if (clang_type->isSignedIntegerType()) + EncodeSInt64(Node->getValue(), clang_type_size); + else + EncodeUInt64(Node->getValue(), clang_type_size); + } + else + { + // TODO: eventually support integer math over 64 bits, probably using + // APInt as the class. + m_stream.PutHex8(DW_OP_APPLE_error); + } +} + +bool +lldb_private::ClangStmtVisitor::EncodeUInt64 (uint64_t uval, uint32_t bit_size) +{ + // If "bit_size" is zero, then encode "uval" in the most efficient way + if (bit_size <= 8 || (bit_size == 0 && uval <= UINT8_MAX)) + { + m_stream.PutHex8 (DW_OP_const1u); + m_stream.PutHex8 (uval); + } + else if (bit_size <= 16 || (bit_size == 0 && uval <= UINT16_MAX)) + { + m_stream.PutHex8 (DW_OP_const2u); + m_stream.PutHex16 (uval); + } + else if (bit_size <= 32 || (bit_size == 0 && uval <= UINT32_MAX)) + { + m_stream.PutHex8 (DW_OP_const4u); + m_stream.PutHex32 (uval); + } + else if (bit_size <= 64 || (bit_size == 0)) + { + m_stream.PutHex8 (DW_OP_const8u); + m_stream.PutHex64 (uval); + } + else + { + m_stream.PutHex8 (DW_OP_APPLE_error); + return false; + } + return true; +} + +bool +lldb_private::ClangStmtVisitor::EncodeSInt64 (int64_t sval, uint32_t bit_size) +{ + if (bit_size <= 8 || (bit_size == 0 && INT8_MIN <= sval && sval <= INT8_MAX)) + { + m_stream.PutHex8 (DW_OP_const1s); + m_stream.PutHex8 (sval); + } + else if (bit_size <= 16 || (bit_size == 0 && INT16_MIN <= sval && sval <= INT16_MAX)) + { + m_stream.PutHex8 (DW_OP_const2s); + m_stream.PutHex16 (sval); + } + else if (bit_size <= 32 || (bit_size == 0 && INT32_MIN <= sval && sval <= INT32_MAX)) + { + m_stream.PutHex8 (DW_OP_const4s); + m_stream.PutHex32 (sval); + } + else if (bit_size <= 64 || (bit_size == 0)) + { + m_stream.PutHex8 (DW_OP_const8s); + m_stream.PutHex64 (sval); + } + else + { + m_stream.PutHex8 (DW_OP_APPLE_error); + return false; + } + return true; +} + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitIntegerLiteral (clang::IntegerLiteral *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + const llvm::APInt &ap_int = Node->getValue(); + if (ap_int.getBitWidth() <= 64) + { + clang::QualType clang_type = Node->getType(); + uint64_t clang_type_size = m_ast_context.getTypeSize (clang_type); + // Encode the integer into our DWARF expression + if (clang_type->isSignedIntegerType()) + EncodeSInt64(ap_int.getLimitedValue(), clang_type_size); + else + EncodeUInt64(ap_int.getLimitedValue(), clang_type_size); + } + else + { + // TODO: eventually support integer math over 64 bits, probably using + // APInt as the class. + m_stream.PutHex8(DW_OP_APPLE_error); + } +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitFloatingLiteral (clang::FloatingLiteral *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + const llvm::APFloat &ap_float = Node->getValue(); + // Put the length of the float in bytes into a single byte + llvm::APInt ap_int(ap_float.bitcastToAPInt()); + const unsigned byte_size = ap_int.getBitWidth() / CHAR_BIT; + if (byte_size == sizeof(float)) + { + if (sizeof(float) == 4) + { + m_stream.PutHex8(DW_OP_APPLE_constf); + m_stream.PutHex8 (byte_size); + m_stream.PutHex32 (ap_int.getLimitedValue()); + return; + } + else if (sizeof(float) == 8) + { + m_stream.PutHex8(DW_OP_APPLE_constf); + m_stream.PutHex8 (byte_size); + m_stream.PutHex64 (ap_int.getLimitedValue()); + return; + } + } + else if (byte_size == sizeof(double)) + { + if (sizeof(double) == 4) + { + m_stream.PutHex8(DW_OP_APPLE_constf); + m_stream.PutHex8 (byte_size); + m_stream.PutHex32 (ap_int.getLimitedValue()); + return; + } + else if (sizeof(double) == 8) + { + m_stream.PutHex8(DW_OP_APPLE_constf); + m_stream.PutHex8 (byte_size); + m_stream.PutHex64 (ap_int.getLimitedValue()); + return; + } + } + else if (byte_size == sizeof(long double)) + { + if (sizeof(long double) == 8) + { + m_stream.PutHex8(DW_OP_APPLE_constf); + m_stream.PutHex8 (byte_size); + m_stream.PutHex64 (ap_int.getLimitedValue()); + return; + } + } + // TODO: eventually support float constants of all sizes using + // APFloat as the class. + m_stream.PutHex8(DW_OP_APPLE_error); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitStringLiteral (clang::StringLiteral *Str) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + + size_t byte_length = Str->getByteLength(); + bool is_wide = Str->isWide(); + + size_t new_length = byte_length + (is_wide ? 1 : 2); + + uint8_t null_terminated_string[new_length]; + + memcpy(&null_terminated_string[0], Str->getStrData(), byte_length); + + if(is_wide) + { + null_terminated_string[byte_length] = '\0'; + null_terminated_string[byte_length + 1] = '\0'; + } + else + { + null_terminated_string[byte_length] = '\0'; + } + + Value *val = new Value(null_terminated_string, new_length); + val->SetContext(Value::eContextTypeOpaqueClangQualType, Str->getType().getAsOpaquePtr()); + + uint32_t val_idx = m_variable_list.AppendValue(val); + + m_stream.PutHex8(DW_OP_APPLE_expr_local); + m_stream.PutULEB128(val_idx); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitUnaryOperator (clang::UnaryOperator *unary_op) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + + Visit(unary_op->getSubExpr()); + + switch (unary_op->getOpcode()) + { + case clang::UnaryOperator::PostInc: + // Duplciate the top of stack value (which must be something that can + // be assignable/incremented) and push its current value + m_stream.PutHex8 (DW_OP_dup); // x, x + m_stream.PutHex8 (DW_OP_APPLE_value_of); // x, val(x) + m_stream.PutHex8 (DW_OP_swap); // val(x), x + m_stream.PutHex8 (DW_OP_dup); // val(x), x, x + m_stream.PutHex8 (DW_OP_lit1); // val(x), x, x, 1 + m_stream.PutHex8 (DW_OP_plus); // val(x), x, val(x)+1 + m_stream.PutHex8 (DW_OP_APPLE_assign); // val(x), x + m_stream.PutHex8 (DW_OP_drop); // val(x) + break; + + case clang::UnaryOperator::PostDec: + // Duplciate the top of stack value (which must be something that can + // be assignable/incremented) and push its current value + m_stream.PutHex8 (DW_OP_dup); // x, x + m_stream.PutHex8 (DW_OP_APPLE_value_of); // x, val(x) + m_stream.PutHex8 (DW_OP_swap); // val(x), x + m_stream.PutHex8 (DW_OP_dup); // val(x), x, x + m_stream.PutHex8 (DW_OP_lit1); // val(x), x, x, 1 + m_stream.PutHex8 (DW_OP_minus); // val(x), x, val(x)-1 + m_stream.PutHex8 (DW_OP_APPLE_assign); // val(x), x + m_stream.PutHex8 (DW_OP_drop); // val(x) + break; + + case clang::UnaryOperator::PreInc: + m_stream.PutHex8 (DW_OP_dup); // x, x + m_stream.PutHex8 (DW_OP_APPLE_value_of); // x, val(x) + m_stream.PutHex8 (DW_OP_lit1); // x, val(x), 1 + m_stream.PutHex8 (DW_OP_plus); // x, val(x)+1 + m_stream.PutHex8 (DW_OP_APPLE_assign); // x with new value + break; + + case clang::UnaryOperator::PreDec: + m_stream.PutHex8 (DW_OP_dup); // x, x + m_stream.PutHex8 (DW_OP_APPLE_value_of); // x, val(x) + m_stream.PutHex8 (DW_OP_lit1); // x, val(x), 1 + m_stream.PutHex8 (DW_OP_minus); // x, val(x)-1 + m_stream.PutHex8 (DW_OP_APPLE_assign); // x with new value + break; + + case clang::UnaryOperator::AddrOf: + m_stream.PutHex8 (DW_OP_APPLE_address_of); + break; + + case clang::UnaryOperator::Deref: + m_stream.PutHex8 (DW_OP_APPLE_deref_type); + break; + + case clang::UnaryOperator::Plus: + m_stream.PutHex8 (DW_OP_abs); + break; + + case clang::UnaryOperator::Minus: + m_stream.PutHex8 (DW_OP_neg); + break; + + case clang::UnaryOperator::Not: + m_stream.PutHex8 (DW_OP_not); + break; + + case clang::UnaryOperator::LNot: + m_stream.PutHex8 (DW_OP_lit0); + m_stream.PutHex8 (DW_OP_eq); + break; + + case clang::UnaryOperator::Real: + m_stream.PutHex8(DW_OP_APPLE_error); + break; + + case clang::UnaryOperator::Imag: + m_stream.PutHex8(DW_OP_APPLE_error); + break; + + case clang::UnaryOperator::Extension: + m_stream.PutHex8(DW_OP_APPLE_error); + break; + + case clang::UnaryOperator::OffsetOf: + break; + + default: + assert(!"Unknown unary operator!"); + break; + } +} + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitCastExpr (clang::CastExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +// CastExpr::CastKind cast_kind = Node->getCastKind(); +// switch (cast_kind) +// { +// case CastExpr::CK_Unknown: +// case CastExpr::CK_BitCast: // Used for reinterpret_cast. +// case CastExpr::CK_NoOp: // Used for const_cast. +// case CastExpr::CK_BaseToDerived: // Base to derived class casts. +// case CastExpr::CK_DerivedToBase: // Derived to base class casts. +// case CastExpr::CK_Dynamic: // Dynamic cast. +// case CastExpr::CK_ToUnion: // Cast to union (GCC extension). +// case CastExpr::CK_ArrayToPointerDecay: // Array to pointer decay. +// case CastExpr::CK_FunctionToPointerDecay: // Function to pointer decay. +// case CastExpr::CK_NullToMemberPointer: // Null pointer to member pointer. +// case CastExpr::CK_BaseToDerivedMemberPointer: // Member pointer in base class to member pointer in derived class. +// case CastExpr::CK_DerivedToBaseMemberPointer: // Member pointer in derived class to member pointer in base class. +// case CastExpr::CK_UserDefinedConversion: // Conversion using a user defined type conversion function. +// case CastExpr::CK_ConstructorConversion: // Conversion by constructor +// case CastExpr::CK_IntegralToPointer: // Integral to pointer +// case CastExpr::CK_PointerToIntegral: // Pointer to integral +// case CastExpr::CK_ToVoid: // Cast to void +// case CastExpr::CK_VectorSplat: // Casting from an integer/floating type to an extended +// // vector type with the same element type as the src type. Splats the +// // src expression into the destination expression. +// case CastExpr::CK_IntegralCast: // Casting between integral types of different size. +// case CastExpr::CK_IntegralToFloating: // Integral to floating point. +// case CastExpr::CK_FloatingToIntegral: // Floating point to integral. +// case CastExpr::CK_FloatingCast: // Casting between floating types of different size. +// m_stream.PutHex8(DW_OP_APPLE_error); +// break; +// } + uint32_t cast_type_count = 0; + lldb_private::Scalar::Type cast_type_encoding = GetScalarTypeForClangType (m_ast_context, Node->getType(), cast_type_count); + + + Visit (Node->getSubExpr()); + + // Simple scalar cast + if (cast_type_encoding != lldb_private::Scalar::e_void && cast_type_count == 1) + { + // Only cast if our scalar types mismatch + uint32_t castee_type_count = 0; + lldb_private::Scalar::Type castee_type_encoding = GetScalarTypeForClangType (m_ast_context, Node->getSubExpr()->getType(), castee_type_count); + if (cast_type_encoding != castee_type_encoding && + castee_type_encoding != lldb_private::Scalar::e_void) + { + m_stream.PutHex8(DW_OP_APPLE_scalar_cast); + m_stream.PutHex8(cast_type_encoding); + } + } + else + { + // Handle more complex casts with clang types soon! + m_stream.PutHex8(DW_OP_APPLE_error); + } +} + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitArraySubscriptExpr (clang::ArraySubscriptExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + Visit (Node->getBase()); + Visit (Node->getIdx()); + m_stream.PutHex8(DW_OP_APPLE_array_ref); +} + +// +//CLANG_STMT_RESULT +//lldb_private::ClangStmtVisitor::VisitImplicitCastExpr (clang::ImplicitCastExpr *Node) +//{ +// DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +// m_stream.PutHex8(DW_OP_APPLE_scalar_cast); +// Visit (Node->getSubExpr()); +//} + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitSizeOfAlignOfExpr (clang::SizeOfAlignOfExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitMemberExpr (clang::MemberExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + clang::Expr *parent = Node->getBase(); + Visit (parent); + clang::QualType parent_clang_type = parent->getType(); + clang::NamedDecl *member_named_decl = cast<clang::NamedDecl>(Node->getMemberDecl()->getCanonicalDecl()); + +// DeclarationName member_name = member->getDeclName(); + + clang::Type::TypeClass parent_type_class = parent_clang_type->getTypeClass(); + if (parent_type_class == clang::Type::Pointer) + { + clang::PointerType *pointer_type = cast<clang::PointerType>(parent_clang_type.getTypePtr()); + parent_clang_type = pointer_type->getPointeeType(); + parent_type_class = parent_clang_type->getTypeClass(); + } + + switch (parent_type_class) + { + case clang::Type::Record: + { + const clang::RecordType *record_type = cast<clang::RecordType>(parent_clang_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + assert(record_decl); + const clang::ASTRecordLayout &record_layout = m_ast_context.getASTRecordLayout(record_decl); + uint32_t field_idx = 0; + clang::RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx) + { + clang::NamedDecl *field_named_decl = cast<clang::NamedDecl>(field->getCanonicalDecl()); + if (field_named_decl == member_named_decl) + { + std::pair<uint64_t, unsigned> field_type_info = m_ast_context.getTypeInfo(field->getType()); + uint64_t field_bit_offset = record_layout.getFieldOffset (field_idx); + uint64_t field_byte_offset = field_bit_offset / 8; + uint32_t field_bitfield_bit_size = 0; + //uint32_t field_bitfield_bit_offset = field_bit_offset % 8; + + if (field->isBitField()) + { + clang::Expr* bit_width_expr = field->getBitWidth(); + if (bit_width_expr) + { + llvm::APSInt bit_width_apsint; + if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, m_ast_context)) + { + field_bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX); + } + } + } + + if (Node->isArrow()) + { + m_stream.PutHex8(DW_OP_deref); + } + else + { + m_stream.PutHex8(DW_OP_APPLE_address_of); + } + + if (field_byte_offset) + { + if (EncodeUInt64(field_byte_offset, 0)) + { + m_stream.PutHex8(DW_OP_plus); + } + } + m_stream.PutHex8(DW_OP_APPLE_clang_cast); + m_stream.PutPointer(field->getType().getAsOpaquePtr()); + break; + } + } + } + break; + + default: + assert(!"Unhandled MemberExpr"); + break; + } +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitExtVectorElementExpr (clang::ExtVectorElementExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitParenExpr(clang::ParenExpr *paren_expr) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + Visit (paren_expr->getSubExpr()); +} + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitInitListExpr (clang::InitListExpr *init_list_expr) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitBinaryOperator (clang::BinaryOperator *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); + + Visit(Node->getLHS()); + Visit(Node->getRHS()); + + switch (Node->getOpcode()) + { + default: assert(0 && "Unknown binary operator!"); + case clang::BinaryOperator::PtrMemD: m_stream.PutHex8(DW_OP_APPLE_error); break; + case clang::BinaryOperator::PtrMemI: m_stream.PutHex8(DW_OP_APPLE_error); break; + case clang::BinaryOperator::Mul: m_stream.PutHex8(DW_OP_mul); break; + case clang::BinaryOperator::Div: m_stream.PutHex8(DW_OP_div); break; + case clang::BinaryOperator::Rem: m_stream.PutHex8(DW_OP_mod); break; + case clang::BinaryOperator::Add: m_stream.PutHex8(DW_OP_plus); break; + case clang::BinaryOperator::Sub: m_stream.PutHex8(DW_OP_minus); break; + case clang::BinaryOperator::Shl: m_stream.PutHex8(DW_OP_shl); break; + case clang::BinaryOperator::Shr: m_stream.PutHex8(DW_OP_shr); break; + case clang::BinaryOperator::LT: m_stream.PutHex8(DW_OP_lt); break; + case clang::BinaryOperator::GT: m_stream.PutHex8(DW_OP_gt); break; + case clang::BinaryOperator::LE: m_stream.PutHex8(DW_OP_le); break; + case clang::BinaryOperator::GE: m_stream.PutHex8(DW_OP_ge); break; + case clang::BinaryOperator::EQ: m_stream.PutHex8(DW_OP_eq); break; + case clang::BinaryOperator::NE: m_stream.PutHex8(DW_OP_ne); break; + case clang::BinaryOperator::And: m_stream.PutHex8(DW_OP_and); break; + case clang::BinaryOperator::Xor: m_stream.PutHex8(DW_OP_xor); break; + case clang::BinaryOperator::Or : m_stream.PutHex8(DW_OP_or); break; + case clang::BinaryOperator::LAnd: + // Do we need to call an operator here on objects? If so + // we will need a DW_OP_apple_logical_and + m_stream.PutHex8(DW_OP_lit0); + m_stream.PutHex8(DW_OP_ne); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_lit0); + m_stream.PutHex8(DW_OP_ne); + m_stream.PutHex8(DW_OP_and); + break; + + case clang::BinaryOperator::LOr : + // Do we need to call an operator here on objects? If so + // we will need a DW_OP_apple_logical_or + m_stream.PutHex8(DW_OP_lit0); + m_stream.PutHex8(DW_OP_ne); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_lit0); + m_stream.PutHex8(DW_OP_ne); + m_stream.PutHex8(DW_OP_or); + break; + + case clang::BinaryOperator::Assign: + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::MulAssign: + m_stream.PutHex8(DW_OP_over); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_mul); + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::DivAssign: + m_stream.PutHex8(DW_OP_over); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_div); + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::RemAssign: + m_stream.PutHex8(DW_OP_over); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_mod); + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::AddAssign: + m_stream.PutHex8(DW_OP_over); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_plus); + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::SubAssign: + m_stream.PutHex8(DW_OP_over); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_minus); + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::ShlAssign: + m_stream.PutHex8(DW_OP_over); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_shl); + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::ShrAssign: + m_stream.PutHex8(DW_OP_over); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_shr); + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::AndAssign: + m_stream.PutHex8(DW_OP_over); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_and); + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::OrAssign: + m_stream.PutHex8(DW_OP_over); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_or); + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::XorAssign: + m_stream.PutHex8(DW_OP_over); + m_stream.PutHex8(DW_OP_swap); + m_stream.PutHex8(DW_OP_xor); + m_stream.PutHex8(DW_OP_APPLE_assign); + break; + + case clang::BinaryOperator::Comma: + // Nothing needs to be done here right? + break; + } +} + + +//CLANG_STMT_RESULT +//lldb_private::ClangStmtVisitor::VisitCompoundAssignOperator (CompoundAssignOperator *Node) +//{ +// DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +// +//} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitAddrLabelExpr (clang::AddrLabelExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitTypesCompatibleExpr (clang::TypesCompatibleExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + + + // C++ +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitCXXNamedCastExpr (clang::CXXNamedCastExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitCXXBoolLiteralExpr (clang::CXXBoolLiteralExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitCXXThisExpr (clang::CXXThisExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitCXXFunctionalCastExpr (clang::CXXFunctionalCastExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + + + // ObjC +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitObjCEncodeExpr (clang::ObjCEncodeExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitObjCMessageExpr (clang::ObjCMessageExpr* Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitObjCSelectorExpr (clang::ObjCSelectorExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitObjCProtocolExpr (clang::ObjCProtocolExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitObjCPropertyRefExpr (clang::ObjCPropertyRefExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitObjCImplicitSetterGetterRefExpr (clang::ObjCImplicitSetterGetterRefExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitObjCIvarRefExpr (clang::ObjCIvarRefExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + +CLANG_STMT_RESULT +lldb_private::ClangStmtVisitor::VisitObjCSuperExpr (clang::ObjCSuperExpr *Node) +{ + DEBUG_PRINTF("%s\n", __PRETTY_FUNCTION__); +} + + diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp new file mode 100644 index 00000000000..d7afa36cea7 --- /dev/null +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -0,0 +1,2589 @@ +//===-- DWARFExpression.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/DWARFExpression.h" + +#include <vector> + +#include "lldb/Core/dwarf.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Core/Value.h" + +#include "lldb/Expression/ClangExpressionDeclMap.h" +#include "lldb/Expression/ClangExpressionVariable.h" + +#include "lldb/Host/Host.h" + +#include "lldb/lldb-private-log.h" + +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/Type.h" + +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" + +using namespace lldb; +using namespace lldb_private; + +const char * +DW_OP_value_to_name (uint32_t val) +{ + static char invalid[100]; + switch (val) { + case 0x03: return "DW_OP_addr"; + case 0x06: return "DW_OP_deref"; + case 0x08: return "DW_OP_const1u"; + case 0x09: return "DW_OP_const1s"; + case 0x0a: return "DW_OP_const2u"; + case 0x0b: return "DW_OP_const2s"; + case 0x0c: return "DW_OP_const4u"; + case 0x0d: return "DW_OP_const4s"; + case 0x0e: return "DW_OP_const8u"; + case 0x0f: return "DW_OP_const8s"; + case 0x10: return "DW_OP_constu"; + case 0x11: return "DW_OP_consts"; + case 0x12: return "DW_OP_dup"; + case 0x13: return "DW_OP_drop"; + case 0x14: return "DW_OP_over"; + case 0x15: return "DW_OP_pick"; + case 0x16: return "DW_OP_swap"; + case 0x17: return "DW_OP_rot"; + case 0x18: return "DW_OP_xderef"; + case 0x19: return "DW_OP_abs"; + case 0x1a: return "DW_OP_and"; + case 0x1b: return "DW_OP_div"; + case 0x1c: return "DW_OP_minus"; + case 0x1d: return "DW_OP_mod"; + case 0x1e: return "DW_OP_mul"; + case 0x1f: return "DW_OP_neg"; + case 0x20: return "DW_OP_not"; + case 0x21: return "DW_OP_or"; + case 0x22: return "DW_OP_plus"; + case 0x23: return "DW_OP_plus_uconst"; + case 0x24: return "DW_OP_shl"; + case 0x25: return "DW_OP_shr"; + case 0x26: return "DW_OP_shra"; + case 0x27: return "DW_OP_xor"; + case 0x2f: return "DW_OP_skip"; + case 0x28: return "DW_OP_bra"; + case 0x29: return "DW_OP_eq"; + case 0x2a: return "DW_OP_ge"; + case 0x2b: return "DW_OP_gt"; + case 0x2c: return "DW_OP_le"; + case 0x2d: return "DW_OP_lt"; + case 0x2e: return "DW_OP_ne"; + case 0x30: return "DW_OP_lit0"; + case 0x31: return "DW_OP_lit1"; + case 0x32: return "DW_OP_lit2"; + case 0x33: return "DW_OP_lit3"; + case 0x34: return "DW_OP_lit4"; + case 0x35: return "DW_OP_lit5"; + case 0x36: return "DW_OP_lit6"; + case 0x37: return "DW_OP_lit7"; + case 0x38: return "DW_OP_lit8"; + case 0x39: return "DW_OP_lit9"; + case 0x3a: return "DW_OP_lit10"; + case 0x3b: return "DW_OP_lit11"; + case 0x3c: return "DW_OP_lit12"; + case 0x3d: return "DW_OP_lit13"; + case 0x3e: return "DW_OP_lit14"; + case 0x3f: return "DW_OP_lit15"; + case 0x40: return "DW_OP_lit16"; + case 0x41: return "DW_OP_lit17"; + case 0x42: return "DW_OP_lit18"; + case 0x43: return "DW_OP_lit19"; + case 0x44: return "DW_OP_lit20"; + case 0x45: return "DW_OP_lit21"; + case 0x46: return "DW_OP_lit22"; + case 0x47: return "DW_OP_lit23"; + case 0x48: return "DW_OP_lit24"; + case 0x49: return "DW_OP_lit25"; + case 0x4a: return "DW_OP_lit26"; + case 0x4b: return "DW_OP_lit27"; + case 0x4c: return "DW_OP_lit28"; + case 0x4d: return "DW_OP_lit29"; + case 0x4e: return "DW_OP_lit30"; + case 0x4f: return "DW_OP_lit31"; + case 0x50: return "DW_OP_reg0"; + case 0x51: return "DW_OP_reg1"; + case 0x52: return "DW_OP_reg2"; + case 0x53: return "DW_OP_reg3"; + case 0x54: return "DW_OP_reg4"; + case 0x55: return "DW_OP_reg5"; + case 0x56: return "DW_OP_reg6"; + case 0x57: return "DW_OP_reg7"; + case 0x58: return "DW_OP_reg8"; + case 0x59: return "DW_OP_reg9"; + case 0x5a: return "DW_OP_reg10"; + case 0x5b: return "DW_OP_reg11"; + case 0x5c: return "DW_OP_reg12"; + case 0x5d: return "DW_OP_reg13"; + case 0x5e: return "DW_OP_reg14"; + case 0x5f: return "DW_OP_reg15"; + case 0x60: return "DW_OP_reg16"; + case 0x61: return "DW_OP_reg17"; + case 0x62: return "DW_OP_reg18"; + case 0x63: return "DW_OP_reg19"; + case 0x64: return "DW_OP_reg20"; + case 0x65: return "DW_OP_reg21"; + case 0x66: return "DW_OP_reg22"; + case 0x67: return "DW_OP_reg23"; + case 0x68: return "DW_OP_reg24"; + case 0x69: return "DW_OP_reg25"; + case 0x6a: return "DW_OP_reg26"; + case 0x6b: return "DW_OP_reg27"; + case 0x6c: return "DW_OP_reg28"; + case 0x6d: return "DW_OP_reg29"; + case 0x6e: return "DW_OP_reg30"; + case 0x6f: return "DW_OP_reg31"; + case 0x70: return "DW_OP_breg0"; + case 0x71: return "DW_OP_breg1"; + case 0x72: return "DW_OP_breg2"; + case 0x73: return "DW_OP_breg3"; + case 0x74: return "DW_OP_breg4"; + case 0x75: return "DW_OP_breg5"; + case 0x76: return "DW_OP_breg6"; + case 0x77: return "DW_OP_breg7"; + case 0x78: return "DW_OP_breg8"; + case 0x79: return "DW_OP_breg9"; + case 0x7a: return "DW_OP_breg10"; + case 0x7b: return "DW_OP_breg11"; + case 0x7c: return "DW_OP_breg12"; + case 0x7d: return "DW_OP_breg13"; + case 0x7e: return "DW_OP_breg14"; + case 0x7f: return "DW_OP_breg15"; + case 0x80: return "DW_OP_breg16"; + case 0x81: return "DW_OP_breg17"; + case 0x82: return "DW_OP_breg18"; + case 0x83: return "DW_OP_breg19"; + case 0x84: return "DW_OP_breg20"; + case 0x85: return "DW_OP_breg21"; + case 0x86: return "DW_OP_breg22"; + case 0x87: return "DW_OP_breg23"; + case 0x88: return "DW_OP_breg24"; + case 0x89: return "DW_OP_breg25"; + case 0x8a: return "DW_OP_breg26"; + case 0x8b: return "DW_OP_breg27"; + case 0x8c: return "DW_OP_breg28"; + case 0x8d: return "DW_OP_breg29"; + case 0x8e: return "DW_OP_breg30"; + case 0x8f: return "DW_OP_breg31"; + case 0x90: return "DW_OP_regx"; + case 0x91: return "DW_OP_fbreg"; + case 0x92: return "DW_OP_bregx"; + case 0x93: return "DW_OP_piece"; + case 0x94: return "DW_OP_deref_size"; + case 0x95: return "DW_OP_xderef_size"; + case 0x96: return "DW_OP_nop"; + case 0x97: return "DW_OP_push_object_address"; + case 0x98: return "DW_OP_call2"; + case 0x99: return "DW_OP_call4"; + case 0x9a: return "DW_OP_call_ref"; + case DW_OP_APPLE_array_ref: return "DW_OP_APPLE_array_ref"; + case DW_OP_APPLE_extern: return "DW_OP_APPLE_extern"; + case DW_OP_APPLE_uninit: return "DW_OP_APPLE_uninit"; + case DW_OP_APPLE_assign: return "DW_OP_APPLE_assign"; + case DW_OP_APPLE_address_of: return "DW_OP_APPLE_address_of"; + case DW_OP_APPLE_value_of: return "DW_OP_APPLE_value_of"; + case DW_OP_APPLE_deref_type: return "DW_OP_APPLE_deref_type"; + case DW_OP_APPLE_expr_local: return "DW_OP_APPLE_expr_local"; + case DW_OP_APPLE_constf: return "DW_OP_APPLE_constf"; + case DW_OP_APPLE_scalar_cast: return "DW_OP_APPLE_scalar_cast"; + case DW_OP_APPLE_clang_cast: return "DW_OP_APPLE_clang_cast"; + case DW_OP_APPLE_clear: return "DW_OP_APPLE_clear"; + case DW_OP_APPLE_error: return "DW_OP_APPLE_error"; + default: + snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val); + return invalid; + } +} + + +//---------------------------------------------------------------------- +// DWARFExpression constructor +//---------------------------------------------------------------------- +DWARFExpression::DWARFExpression() : + m_data(), + m_reg_kind (eRegisterKindDWARF), + m_loclist_base_addr(), + m_expr_locals (NULL), + m_decl_map (NULL) +{ +} + +DWARFExpression::DWARFExpression(const DWARFExpression& rhs) : + m_data(rhs.m_data), + m_reg_kind (rhs.m_reg_kind), + m_loclist_base_addr(rhs.m_loclist_base_addr), + m_expr_locals (rhs.m_expr_locals), + m_decl_map (rhs.m_decl_map) +{ +} + + +DWARFExpression::DWARFExpression(const DataExtractor& data, uint32_t data_offset, uint32_t data_length, const Address* loclist_base_addr_ptr) : + m_data(data, data_offset, data_length), + m_reg_kind (eRegisterKindDWARF), + m_loclist_base_addr(), + m_expr_locals (NULL), + m_decl_map (NULL) +{ + if (loclist_base_addr_ptr) + m_loclist_base_addr = *loclist_base_addr_ptr; +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +DWARFExpression::~DWARFExpression() +{ +} + + +bool +DWARFExpression::IsValid() const +{ + return m_data.GetByteSize() > 0; +} + + +void +DWARFExpression::SetExpressionLocalVariableList (ClangExpressionVariableList *locals) +{ + m_expr_locals = locals; +} + +void +DWARFExpression::SetExpressionDeclMap (ClangExpressionDeclMap *decl_map) +{ + m_decl_map = decl_map; +} + +void +DWARFExpression::SetOpcodeData (const DataExtractor& data, const Address* loclist_base_addr_ptr) +{ + m_data = data; + if (loclist_base_addr_ptr != NULL) + m_loclist_base_addr = *loclist_base_addr_ptr; + else + m_loclist_base_addr.Clear(); +} + +void +DWARFExpression::SetOpcodeData (const DataExtractor& data, uint32_t data_offset, uint32_t data_length, const Address* loclist_base_addr_ptr) +{ + m_data.SetData(data, data_offset, data_length); + if (loclist_base_addr_ptr != NULL) + m_loclist_base_addr = *loclist_base_addr_ptr; + else + m_loclist_base_addr.Clear(); +} + +void +DWARFExpression::DumpLocation (Stream *s, uint32_t offset, uint32_t length, lldb::DescriptionLevel level) const +{ + if (!m_data.ValidOffsetForDataOfSize(offset, length)) + return; + const uint32_t start_offset = offset; + const uint32_t end_offset = offset + length; + while (m_data.ValidOffset(offset) && offset < end_offset) + { + const uint32_t op_offset = offset; + const uint8_t op = m_data.GetU8(&offset); + + switch (level) + { + case lldb::eDescriptionLevelBrief: + if (offset > start_offset) + s->PutChar(' '); + break; + + case lldb::eDescriptionLevelFull: + case lldb::eDescriptionLevelVerbose: + if (offset > start_offset) + s->EOL(); + s->Indent(); + if (level == lldb::eDescriptionLevelFull) + break; + // Fall through for verbose and print offset and DW_OP prefix.. + s->Printf("0x%8.8x: %s", op_offset, op >= DW_OP_APPLE_uninit ? "DW_OP_APPLE_" : "DW_OP_"); + break; + } + + switch (op) + { + case DW_OP_addr: *s << "addr(" << m_data.GetAddress(&offset) << ") "; break; // 0x03 1 address + case DW_OP_deref: *s << "deref"; break; // 0x06 + case DW_OP_const1u: s->Printf("const1u(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x08 1 1-byte constant + case DW_OP_const1s: s->Printf("const1s(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x09 1 1-byte constant + case DW_OP_const2u: s->Printf("const2u(0x%4.4x) ", m_data.GetU16(&offset)); break; // 0x0a 1 2-byte constant + case DW_OP_const2s: s->Printf("const2s(0x%4.4x) ", m_data.GetU16(&offset)); break; // 0x0b 1 2-byte constant + case DW_OP_const4u: s->Printf("const4u(0x%8.8x) ", m_data.GetU32(&offset)); break; // 0x0c 1 4-byte constant + case DW_OP_const4s: s->Printf("const4s(0x%8.8x) ", m_data.GetU32(&offset)); break; // 0x0d 1 4-byte constant + case DW_OP_const8u: s->Printf("const8u(0x%16.16llx) ", m_data.GetU64(&offset)); break; // 0x0e 1 8-byte constant + case DW_OP_const8s: s->Printf("const8s(0x%16.16llx) ", m_data.GetU64(&offset)); break; // 0x0f 1 8-byte constant + case DW_OP_constu: s->Printf("constu(0x%x) ", m_data.GetULEB128(&offset)); break; // 0x10 1 ULEB128 constant + case DW_OP_consts: s->Printf("consts(0x%x) ", m_data.GetSLEB128(&offset)); break; // 0x11 1 SLEB128 constant + case DW_OP_dup: s->PutCString("dup"); break; // 0x12 + case DW_OP_drop: s->PutCString("drop"); break; // 0x13 + case DW_OP_over: s->PutCString("over"); break; // 0x14 + case DW_OP_pick: s->Printf("pick(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x15 1 1-byte stack index + case DW_OP_swap: s->PutCString("swap"); break; // 0x16 + case DW_OP_rot: s->PutCString("rot"); break; // 0x17 + case DW_OP_xderef: s->PutCString("xderef"); break; // 0x18 + case DW_OP_abs: s->PutCString("abs"); break; // 0x19 + case DW_OP_and: s->PutCString("and"); break; // 0x1a + case DW_OP_div: s->PutCString("div"); break; // 0x1b + case DW_OP_minus: s->PutCString("minus"); break; // 0x1c + case DW_OP_mod: s->PutCString("mod"); break; // 0x1d + case DW_OP_mul: s->PutCString("mul"); break; // 0x1e + case DW_OP_neg: s->PutCString("neg"); break; // 0x1f + case DW_OP_not: s->PutCString("not"); break; // 0x20 + case DW_OP_or: s->PutCString("or"); break; // 0x21 + case DW_OP_plus: s->PutCString("plus"); break; // 0x22 + case DW_OP_plus_uconst: // 0x23 1 ULEB128 addend + s->Printf("plus_uconst(0x%x) ", m_data.GetULEB128(&offset)); + break; + + case DW_OP_shl: s->PutCString("shl"); break; // 0x24 + case DW_OP_shr: s->PutCString("shr"); break; // 0x25 + case DW_OP_shra: s->PutCString("shra"); break; // 0x26 + case DW_OP_xor: s->PutCString("xor"); break; // 0x27 + case DW_OP_skip: s->Printf("skip(0x%4.4x)", m_data.GetU16(&offset)); break; // 0x2f 1 signed 2-byte constant + case DW_OP_bra: s->Printf("bra(0x%4.4x)", m_data.GetU16(&offset)); break; // 0x28 1 signed 2-byte constant + case DW_OP_eq: s->PutCString("eq"); break; // 0x29 + case DW_OP_ge: s->PutCString("ge"); break; // 0x2a + case DW_OP_gt: s->PutCString("gt"); break; // 0x2b + case DW_OP_le: s->PutCString("le"); break; // 0x2c + case DW_OP_lt: s->PutCString("lt"); break; // 0x2d + case DW_OP_ne: s->PutCString("ne"); break; // 0x2e + + case DW_OP_lit0: // 0x30 + case DW_OP_lit1: // 0x31 + case DW_OP_lit2: // 0x32 + case DW_OP_lit3: // 0x33 + case DW_OP_lit4: // 0x34 + case DW_OP_lit5: // 0x35 + case DW_OP_lit6: // 0x36 + case DW_OP_lit7: // 0x37 + case DW_OP_lit8: // 0x38 + case DW_OP_lit9: // 0x39 + case DW_OP_lit10: // 0x3A + case DW_OP_lit11: // 0x3B + case DW_OP_lit12: // 0x3C + case DW_OP_lit13: // 0x3D + case DW_OP_lit14: // 0x3E + case DW_OP_lit15: // 0x3F + case DW_OP_lit16: // 0x40 + case DW_OP_lit17: // 0x41 + case DW_OP_lit18: // 0x42 + case DW_OP_lit19: // 0x43 + case DW_OP_lit20: // 0x44 + case DW_OP_lit21: // 0x45 + case DW_OP_lit22: // 0x46 + case DW_OP_lit23: // 0x47 + case DW_OP_lit24: // 0x48 + case DW_OP_lit25: // 0x49 + case DW_OP_lit26: // 0x4A + case DW_OP_lit27: // 0x4B + case DW_OP_lit28: // 0x4C + case DW_OP_lit29: // 0x4D + case DW_OP_lit30: // 0x4E + case DW_OP_lit31: s->Printf("lit%i", op - DW_OP_lit0); break; // 0x4f + + case DW_OP_reg0: // 0x50 + case DW_OP_reg1: // 0x51 + case DW_OP_reg2: // 0x52 + case DW_OP_reg3: // 0x53 + case DW_OP_reg4: // 0x54 + case DW_OP_reg5: // 0x55 + case DW_OP_reg6: // 0x56 + case DW_OP_reg7: // 0x57 + case DW_OP_reg8: // 0x58 + case DW_OP_reg9: // 0x59 + case DW_OP_reg10: // 0x5A + case DW_OP_reg11: // 0x5B + case DW_OP_reg12: // 0x5C + case DW_OP_reg13: // 0x5D + case DW_OP_reg14: // 0x5E + case DW_OP_reg15: // 0x5F + case DW_OP_reg16: // 0x60 + case DW_OP_reg17: // 0x61 + case DW_OP_reg18: // 0x62 + case DW_OP_reg19: // 0x63 + case DW_OP_reg20: // 0x64 + case DW_OP_reg21: // 0x65 + case DW_OP_reg22: // 0x66 + case DW_OP_reg23: // 0x67 + case DW_OP_reg24: // 0x68 + case DW_OP_reg25: // 0x69 + case DW_OP_reg26: // 0x6A + case DW_OP_reg27: // 0x6B + case DW_OP_reg28: // 0x6C + case DW_OP_reg29: // 0x6D + case DW_OP_reg30: // 0x6E + case DW_OP_reg31: s->Printf("reg%i", op - DW_OP_reg0); break; // 0x6f + + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: s->Printf("breg%i(0x%x)", op - DW_OP_breg0, m_data.GetULEB128(&offset)); break; + + case DW_OP_regx: // 0x90 1 ULEB128 register + s->Printf("regx(0x%x)", m_data.GetULEB128(&offset)); + break; + case DW_OP_fbreg: // 0x91 1 SLEB128 offset + s->Printf("fbreg(0x%x)",m_data.GetSLEB128(&offset)); + break; + case DW_OP_bregx: // 0x92 2 ULEB128 register followed by SLEB128 offset + s->Printf("bregx(0x%x, 0x%x)", m_data.GetULEB128(&offset), m_data.GetSLEB128(&offset)); + break; + case DW_OP_piece: // 0x93 1 ULEB128 size of piece addressed + s->Printf("piece(0x%x)", m_data.GetULEB128(&offset)); + break; + case DW_OP_deref_size: // 0x94 1 1-byte size of data retrieved + s->Printf("deref_size(0x%2.2x)", m_data.GetU8(&offset)); + break; + case DW_OP_xderef_size: // 0x95 1 1-byte size of data retrieved + s->Printf("xderef_size(0x%2.2x)", m_data.GetU8(&offset)); + break; + case DW_OP_nop: s->PutCString("nop"); break; // 0x96 + case DW_OP_push_object_address: s->PutCString("push_object_address"); break; // 0x97 DWARF3 + case DW_OP_call2: // 0x98 DWARF3 1 2-byte offset of DIE + s->Printf("call2(0x%4.4x)", m_data.GetU16(&offset)); + break; + case DW_OP_call4: // 0x99 DWARF3 1 4-byte offset of DIE + s->Printf("call4(0x%8.8x)", m_data.GetU32(&offset)); + break; + case DW_OP_call_ref: // 0x9a DWARF3 1 4- or 8-byte offset of DIE + s->Printf("call_ref(0x%8.8llx)", m_data.GetAddress(&offset)); + break; +// case DW_OP_form_tls_address: s << "form_tls_address"; break; // 0x9b DWARF3 +// case DW_OP_call_frame_cfa: s << "call_frame_cfa"; break; // 0x9c DWARF3 +// case DW_OP_bit_piece: // 0x9d DWARF3 2 +// s->Printf("bit_piece(0x%x, 0x%x)", m_data.GetULEB128(&offset), m_data.GetULEB128(&offset)); +// break; +// case DW_OP_lo_user: s->PutCString("lo_user"); break; // 0xe0 +// case DW_OP_hi_user: s->PutCString("hi_user"); break; // 0xff + case DW_OP_APPLE_extern: + s->Printf("extern(%u)", m_data.GetULEB128(&offset)); + break; + case DW_OP_APPLE_array_ref: + s->PutCString("array_ref"); + break; + case DW_OP_APPLE_uninit: + s->PutCString("uninit"); // 0xF0 + break; + case DW_OP_APPLE_assign: // 0xF1 - pops value off and assigns it to second item on stack (2nd item must have assignable context) + s->PutCString("assign"); + break; + case DW_OP_APPLE_address_of: // 0xF2 - gets the address of the top stack item (top item must be a variable, or have value_type that is an address already) + s->PutCString("address_of"); + break; + case DW_OP_APPLE_value_of: // 0xF3 - pops the value off the stack and pushes the value of that object (top item must be a variable, or expression local) + s->PutCString("value_of"); + break; + case DW_OP_APPLE_deref_type: // 0xF4 - gets the address of the top stack item (top item must be a variable, or a clang type) + s->PutCString("deref_type"); + break; + case DW_OP_APPLE_expr_local: // 0xF5 - ULEB128 expression local index + s->Printf("expr_local(%u)", m_data.GetULEB128(&offset)); + break; + case DW_OP_APPLE_constf: // 0xF6 - 1 byte float size, followed by constant float data + { + uint8_t float_length = m_data.GetU8(&offset); + s->Printf("constf(<%u> ", float_length); + m_data.Dump(s, offset, eFormatHex, float_length, 1, UINT32_MAX, DW_INVALID_ADDRESS, 0, 0); + s->PutChar(')'); + // Consume the float data + m_data.GetData(&offset, float_length); + } + break; + case DW_OP_APPLE_scalar_cast: + s->Printf("scalar_cast(%s)", Scalar::GetValueTypeAsCString ((Scalar::Type)m_data.GetU8(&offset))); + break; + case DW_OP_APPLE_clang_cast: + { + clang::Type *clang_type = (clang::Type *)m_data.GetMaxU64(&offset, sizeof(void*)); + s->Printf("clang_cast(%p)", clang_type); + } + break; + case DW_OP_APPLE_clear: + s->PutCString("clear"); + break; + case DW_OP_APPLE_error: // 0xFF - Stops expression evaluation and returns an error (no args) + s->PutCString("error"); + break; + } + } +} + +void +DWARFExpression::SetLocationListBaseAddress(Address& base_addr) +{ + m_loclist_base_addr = base_addr; +} + +int +DWARFExpression::GetRegisterKind () +{ + return m_reg_kind; +} + +void +DWARFExpression::SetRegisterKind (int reg_kind) +{ + m_reg_kind = reg_kind; +} + +bool +DWARFExpression::IsLocationList() const +{ + return m_loclist_base_addr.IsSectionOffset(); +} + +void +DWARFExpression::GetDescription (Stream *s, lldb::DescriptionLevel level) const +{ + if (IsLocationList()) + { + // We have a location list + uint32_t offset = 0; + uint32_t count = 0; + Address base_addr(m_loclist_base_addr); + while (m_data.ValidOffset(offset)) + { + lldb::addr_t begin_addr_offset = m_data.GetAddress(&offset); + lldb::addr_t end_addr_offset = m_data.GetAddress(&offset); + if (begin_addr_offset < end_addr_offset) + { + if (count > 0) + s->PutCString(", "); + AddressRange addr_range(base_addr, end_addr_offset - begin_addr_offset); + addr_range.GetBaseAddress().SetOffset(base_addr.GetOffset() + begin_addr_offset); + addr_range.Dump (s, NULL, Address::DumpStyleFileAddress); + s->PutChar('{'); + uint32_t location_length = m_data.GetU16(&offset); + DumpLocation (s, offset, location_length, level); + s->PutChar('}'); + offset += location_length; + } + else if (begin_addr_offset == 0 && end_addr_offset == 0) + { + // The end of the location list is marked by both the start and end offset being zero + break; + } + else + { + if (m_data.GetAddressByteSize() == 4 && begin_addr_offset == 0xFFFFFFFFull || + m_data.GetAddressByteSize() == 8 && begin_addr_offset == 0xFFFFFFFFFFFFFFFFull) + { + // We have a new base address + if (count > 0) + s->PutCString(", "); + *s << "base_addr = " << end_addr_offset; + } + } + + count++; + } + } + else + { + // We have a normal location that contains DW_OP location opcodes + DumpLocation (s, 0, m_data.GetByteSize(), level); + } +} + +static bool +ReadRegisterValueAsScalar +( + ExecutionContext *exe_ctx, + uint32_t reg_kind, + uint32_t reg_num, + Error *error_ptr, + Value &value +) +{ + if (exe_ctx && exe_ctx->frame) + { + RegisterContext *reg_context = exe_ctx->frame->GetRegisterContext(); + + if (reg_context == NULL) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("No register context in frame.\n"); + } + else + { + uint32_t native_reg = reg_context->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num); + if (native_reg == LLDB_INVALID_REGNUM) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("Unable to convert register kind=%u reg_num=%u to a native register number.\n", reg_kind, reg_num); + } + else + { + value.SetValueType (Value::eValueTypeScalar); + value.SetContext (Value::eContextTypeDCRegisterInfo, const_cast<RegisterInfo *>(reg_context->GetRegisterInfoAtIndex(native_reg))); + + if (reg_context->ReadRegisterValue (native_reg, value.GetScalar())) + return true; + + if (error_ptr) + error_ptr->SetErrorStringWithFormat("Failed to read register %u.\n", native_reg); + } + } + } + else + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("Invalid frame in execution context.\n"); + } + return false; +} + +bool +DWARFExpression::LocationListContainsLoadAddress (Process* process, const Address &addr) const +{ + if (IsLocationList()) + { + uint32_t offset = 0; + const addr_t load_addr = addr.GetLoadAddress(process); + + if (load_addr == LLDB_INVALID_ADDRESS) + return false; + + addr_t loc_list_base_addr = m_loclist_base_addr.GetLoadAddress(process); + + if (loc_list_base_addr == LLDB_INVALID_ADDRESS) + return false; + + while (m_data.ValidOffset(offset)) + { + // We need to figure out what the value is for the location. + addr_t lo_pc = m_data.GetAddress(&offset); + addr_t hi_pc = m_data.GetAddress(&offset); + if (lo_pc == 0 && hi_pc == 0) + break; + else + { + lo_pc += loc_list_base_addr; + hi_pc += loc_list_base_addr; + + if (lo_pc <= load_addr && load_addr < hi_pc) + return true; + + offset += m_data.GetU16(&offset); + } + } + } + return false; +} +bool +DWARFExpression::Evaluate +( + ExecutionContextScope *exe_scope, + clang::ASTContext *ast_context, + const Value* initial_value_ptr, + Value& result, + Error *error_ptr +) const +{ + ExecutionContext exe_ctx (exe_scope); + return Evaluate(&exe_ctx, ast_context, initial_value_ptr, result, error_ptr); +} + +bool +DWARFExpression::Evaluate +( + ExecutionContext *exe_ctx, + clang::ASTContext *ast_context, + const Value* initial_value_ptr, + Value& result, + Error *error_ptr +) const +{ + if (IsLocationList()) + { + uint32_t offset = 0; + addr_t pc = exe_ctx->frame->GetPC().GetLoadAddress(exe_ctx->process); + + if (pc == LLDB_INVALID_ADDRESS) + { + if (error_ptr) + error_ptr->SetErrorString("Invalid PC in frame."); + return false; + } + + addr_t loc_list_base_addr = m_loclist_base_addr.GetLoadAddress(exe_ctx->process); + + if (loc_list_base_addr == LLDB_INVALID_ADDRESS) + { + if (error_ptr) + error_ptr->SetErrorString("Out of scope."); + return false; + } + + while (m_data.ValidOffset(offset)) + { + // We need to figure out what the value is for the location. + addr_t lo_pc = m_data.GetAddress(&offset); + addr_t hi_pc = m_data.GetAddress(&offset); + if (lo_pc == 0 && hi_pc == 0) + { + break; + } + else + { + lo_pc += loc_list_base_addr; + hi_pc += loc_list_base_addr; + + uint16_t length = m_data.GetU16(&offset); + + if (length > 0 && lo_pc <= pc && pc < hi_pc) + { + return DWARFExpression::Evaluate (exe_ctx, ast_context, m_data, m_expr_locals, m_decl_map, offset, length, m_reg_kind, initial_value_ptr, result, error_ptr); + } + offset += length; + } + } + if (error_ptr) + error_ptr->SetErrorStringWithFormat("Out of scope.\n", pc); + return false; + } + + // Not a location list, just a single expression. + return DWARFExpression::Evaluate (exe_ctx, ast_context, m_data, m_expr_locals, m_decl_map, 0, m_data.GetByteSize(), m_reg_kind, initial_value_ptr, result, error_ptr); +} + + + +bool +DWARFExpression::Evaluate +( + ExecutionContext *exe_ctx, + clang::ASTContext *ast_context, + const DataExtractor& opcodes, + ClangExpressionVariableList *expr_locals, + ClangExpressionDeclMap *decl_map, + const uint32_t opcodes_offset, + const uint32_t opcodes_length, + const uint32_t reg_kind, + const Value* initial_value_ptr, + Value& result, + Error *error_ptr +) +{ + std::vector<Value> stack; + + if (initial_value_ptr) + stack.push_back(*initial_value_ptr); + + uint32_t offset = opcodes_offset; + const uint32_t end_offset = opcodes_offset + opcodes_length; + Value tmp; + uint32_t reg_num; + + // Make sure all of the data is available in opcodes. + if (!opcodes.ValidOffsetForDataOfSize(opcodes_offset, opcodes_length)) + { + if (error_ptr) + error_ptr->SetErrorString ("Invalid offset and/or length for opcodes buffer."); + return false; + } + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + + + while (opcodes.ValidOffset(offset) && offset < end_offset) + { + const uint32_t op_offset = offset; + const uint8_t op = opcodes.GetU8(&offset); + + if (log) + { + log->Printf("\n"); + size_t count = stack.size(); + for (size_t i=0; i<count; ++i) + { + StreamString new_value; + new_value.Printf("[%zu]", i); + stack[i].Dump(&new_value); + log->Printf("%s", new_value.GetData()); + } + log->Printf("0x%8.8x: %s", op_offset, DW_OP_value_to_name(op)); + } + switch (op) + { + //---------------------------------------------------------------------- + // The DW_OP_addr operation has a single operand that encodes a machine + // address and whose size is the size of an address on the target machine. + //---------------------------------------------------------------------- + case DW_OP_addr: + stack.push_back(opcodes.GetAddress(&offset)); + stack.back().SetValueType (Value::eValueTypeFileAddress); + break; + + //---------------------------------------------------------------------- + // The DW_OP_addr_sect_offset4 is used for any location expressions in + // shared libraries that have a location like: + // DW_OP_addr(0x1000) + // If this address resides in a shared library, then this virtual + // address won't make sense when it is evaluated in the context of a + // running process where shared libraries have been slid. To account for + // this, this new address type where we can store the section pointer + // and a 4 byte offset. + //---------------------------------------------------------------------- +// case DW_OP_addr_sect_offset4: +// { +// result_type = eResultTypeFileAddress; +// lldb::Section *sect = (lldb::Section *)opcodes.GetMaxU64(&offset, sizeof(void *)); +// lldb::addr_t sect_offset = opcodes.GetU32(&offset); +// +// Address so_addr (sect, sect_offset); +// lldb::addr_t load_addr = so_addr.GetLoadAddress(); +// if (load_addr != LLDB_INVALID_ADDRESS) +// { +// // We successfully resolve a file address to a load +// // address. +// stack.push_back(load_addr); +// break; +// } +// else +// { +// // We were able +// if (error_ptr) +// error_ptr->SetErrorStringWithFormat ("Section %s in %s is not currently loaded.\n", sect->GetName().AsCString(), sect->GetModule()->GetFileSpec().GetFilename().AsCString()); +// return false; +// } +// } +// break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_deref + // OPERANDS: none + // DESCRIPTION: Pops the top stack entry and treats it as an address. + // The value retrieved from that address is pushed. The size of the + // data retrieved from the dereferenced address is the size of an + // address on the target machine. + //---------------------------------------------------------------------- + case DW_OP_deref: + { + Value::ValueType value_type = stack.back().GetValueType(); + switch (value_type) + { + case Value::eValueTypeHostAddress: + { + void *src = (void *)stack.back().GetScalar().ULongLong(); + intptr_t ptr; + ::memcpy (&ptr, src, sizeof(void *)); + stack.back().GetScalar() = ptr; + stack.back().ClearContext(); + } + break; + case Value::eValueTypeLoadAddress: + if (exe_ctx) + { + if (exe_ctx->process) + { + lldb::addr_t pointer_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + uint8_t addr_bytes[sizeof(lldb::addr_t)]; + uint32_t addr_size = exe_ctx->process->GetAddressByteSize(); + Error error; + if (exe_ctx->process->ReadMemory(pointer_addr, &addr_bytes, addr_size, error) == addr_size) + { + DataExtractor addr_data(addr_bytes, sizeof(addr_bytes), exe_ctx->process->GetByteOrder(), addr_size); + uint32_t addr_data_offset = 0; + stack.back().GetScalar() = addr_data.GetPointer(&addr_data_offset); + stack.back().ClearContext(); + } + else + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("Failed to dereference pointer from 0x%llx for DW_OP_deref: %s\n", + pointer_addr, + error.AsCString()); + return false; + } + } + else + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("NULL process for DW_OP_deref.\n"); + return false; + } + } + else + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("NULL execution context for DW_OP_deref.\n"); + return false; + } + break; + + default: + break; + } + + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_deref_size + // OPERANDS: 1 + // 1 - uint8_t that specifies the size of the data to dereference. + // DESCRIPTION: Behaves like the DW_OP_deref operation: it pops the top + // stack entry and treats it as an address. The value retrieved from that + // address is pushed. In the DW_OP_deref_size operation, however, the + // size in bytes of the data retrieved from the dereferenced address is + // specified by the single operand. This operand is a 1-byte unsigned + // integral constant whose value may not be larger than the size of an + // address on the target machine. The data retrieved is zero extended + // to the size of an address on the target machine before being pushed + // on the expression stack. + //---------------------------------------------------------------------- + case DW_OP_deref_size: + if (error_ptr) + error_ptr->SetErrorString("Unimplemented opcode: DW_OP_deref_size."); + return false; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_xderef_size + // OPERANDS: 1 + // 1 - uint8_t that specifies the size of the data to dereference. + // DESCRIPTION: Behaves like the DW_OP_xderef operation: the entry at + // the top of the stack is treated as an address. The second stack + // entry is treated as an “address space identifier” for those + // architectures that support multiple address spaces. The top two + // stack elements are popped, a data item is retrieved through an + // implementation-defined address calculation and pushed as the new + // stack top. In the DW_OP_xderef_size operation, however, the size in + // bytes of the data retrieved from the dereferenced address is + // specified by the single operand. This operand is a 1-byte unsigned + // integral constant whose value may not be larger than the size of an + // address on the target machine. The data retrieved is zero extended + // to the size of an address on the target machine before being pushed + // on the expression stack. + //---------------------------------------------------------------------- + case DW_OP_xderef_size: + if (error_ptr) + error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef_size."); + return false; + //---------------------------------------------------------------------- + // OPCODE: DW_OP_xderef + // OPERANDS: none + // DESCRIPTION: Provides an extended dereference mechanism. The entry at + // the top of the stack is treated as an address. The second stack entry + // is treated as an "address space identifier" for those architectures + // that support multiple address spaces. The top two stack elements are + // popped, a data item is retrieved through an implementation-defined + // address calculation and pushed as the new stack top. The size of the + // data retrieved from the dereferenced address is the size of an address + // on the target machine. + //---------------------------------------------------------------------- + case DW_OP_xderef: + if (error_ptr) + error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef."); + return false; + + //---------------------------------------------------------------------- + // All DW_OP_constXXX opcodes have a single operand as noted below: + // + // Opcode Operand 1 + // --------------- ---------------------------------------------------- + // DW_OP_const1u 1-byte unsigned integer constant + // DW_OP_const1s 1-byte signed integer constant + // DW_OP_const2u 2-byte unsigned integer constant + // DW_OP_const2s 2-byte signed integer constant + // DW_OP_const4u 4-byte unsigned integer constant + // DW_OP_const4s 4-byte signed integer constant + // DW_OP_const8u 8-byte unsigned integer constant + // DW_OP_const8s 8-byte signed integer constant + // DW_OP_constu unsigned LEB128 integer constant + // DW_OP_consts signed LEB128 integer constant + //---------------------------------------------------------------------- + case DW_OP_const1u : stack.push_back(( uint8_t)opcodes.GetU8(&offset)); break; + case DW_OP_const1s : stack.push_back(( int8_t)opcodes.GetU8(&offset)); break; + case DW_OP_const2u : stack.push_back((uint16_t)opcodes.GetU16(&offset)); break; + case DW_OP_const2s : stack.push_back(( int16_t)opcodes.GetU16(&offset)); break; + case DW_OP_const4u : stack.push_back((uint32_t)opcodes.GetU32(&offset)); break; + case DW_OP_const4s : stack.push_back(( int32_t)opcodes.GetU32(&offset)); break; + case DW_OP_const8u : stack.push_back((uint64_t)opcodes.GetU64(&offset)); break; + case DW_OP_const8s : stack.push_back(( int64_t)opcodes.GetU64(&offset)); break; + case DW_OP_constu : stack.push_back(opcodes.GetULEB128(&offset)); break; + case DW_OP_consts : stack.push_back(opcodes.GetSLEB128(&offset)); break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_dup + // OPERANDS: none + // DESCRIPTION: duplicates the value at the top of the stack + //---------------------------------------------------------------------- + case DW_OP_dup: + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack empty for DW_OP_dup."); + return false; + } + else + stack.push_back(stack.back()); + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_drop + // OPERANDS: none + // DESCRIPTION: pops the value at the top of the stack + //---------------------------------------------------------------------- + case DW_OP_drop: + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack empty for DW_OP_drop."); + return false; + } + else + stack.pop_back(); + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_over + // OPERANDS: none + // DESCRIPTION: Duplicates the entry currently second in the stack at + // the top of the stack. + //---------------------------------------------------------------------- + case DW_OP_over: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_over."); + return false; + } + else + stack.push_back(stack[stack.size() - 2]); + break; + + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_pick + // OPERANDS: uint8_t index into the current stack + // DESCRIPTION: The stack entry with the specified index (0 through 255, + // inclusive) is pushed on the stack + //---------------------------------------------------------------------- + case DW_OP_pick: + { + uint8_t pick_idx = opcodes.GetU8(&offset); + if (pick_idx < stack.size()) + stack.push_back(stack[pick_idx]); + else + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("Index %u out of range for DW_OP_pick.\n", pick_idx); + return false; + } + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_swap + // OPERANDS: none + // DESCRIPTION: swaps the top two stack entries. The entry at the top + // of the stack becomes the second stack entry, and the second entry + // becomes the top of the stack + //---------------------------------------------------------------------- + case DW_OP_swap: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_swap."); + return false; + } + else + { + tmp = stack.back(); + stack.back() = stack[stack.size() - 2]; + stack[stack.size() - 2] = tmp; + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_rot + // OPERANDS: none + // DESCRIPTION: Rotates the first three stack entries. The entry at + // the top of the stack becomes the third stack entry, the second + // entry becomes the top of the stack, and the third entry becomes + // the second entry. + //---------------------------------------------------------------------- + case DW_OP_rot: + if (stack.size() < 3) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 3 items for DW_OP_rot."); + return false; + } + else + { + size_t last_idx = stack.size() - 1; + Value old_top = stack[last_idx]; + stack[last_idx] = stack[last_idx - 1]; + stack[last_idx - 1] = stack[last_idx - 2]; + stack[last_idx - 2] = old_top; + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_abs + // OPERANDS: none + // DESCRIPTION: pops the top stack entry, interprets it as a signed + // value and pushes its absolute value. If the absolute value can not be + // represented, the result is undefined. + //---------------------------------------------------------------------- + case DW_OP_abs: + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_abs."); + return false; + } + else if (stack.back().ResolveValue(exe_ctx, ast_context).AbsoluteValue() == false) + { + if (error_ptr) + error_ptr->SetErrorString("Failed to take the absolute value of the first stack item."); + return false; + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_and + // OPERANDS: none + // DESCRIPTION: pops the top two stack values, performs a bitwise and + // operation on the two, and pushes the result. + //---------------------------------------------------------------------- + case DW_OP_and: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_and."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) & tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_div + // OPERANDS: none + // DESCRIPTION: pops the top two stack values, divides the former second + // entry by the former top of the stack using signed division, and + // pushes the result. + //---------------------------------------------------------------------- + case DW_OP_div: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_div."); + return false; + } + else + { + tmp = stack.back(); + if (tmp.ResolveValue(exe_ctx, ast_context).IsZero()) + { + if (error_ptr) + error_ptr->SetErrorString("Divide by zero."); + return false; + } + else + { + stack.pop_back(); + stack.back() = stack.back().ResolveValue(exe_ctx, ast_context) / tmp.ResolveValue(exe_ctx, ast_context); + if (!stack.back().ResolveValue(exe_ctx, ast_context).IsValid()) + { + if (error_ptr) + error_ptr->SetErrorString("Divide failed."); + return false; + } + } + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_minus + // OPERANDS: none + // DESCRIPTION: pops the top two stack values, subtracts the former top + // of the stack from the former second entry, and pushes the result. + //---------------------------------------------------------------------- + case DW_OP_minus: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_minus."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) - tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_mod + // OPERANDS: none + // DESCRIPTION: pops the top two stack values and pushes the result of + // the calculation: former second stack entry modulo the former top of + // the stack. + //---------------------------------------------------------------------- + case DW_OP_mod: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_mod."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) % tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_mul + // OPERANDS: none + // DESCRIPTION: pops the top two stack entries, multiplies them + // together, and pushes the result. + //---------------------------------------------------------------------- + case DW_OP_mul: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_mul."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) * tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_neg + // OPERANDS: none + // DESCRIPTION: pops the top stack entry, and pushes its negation. + //---------------------------------------------------------------------- + case DW_OP_neg: + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_neg."); + return false; + } + else + { + if (stack.back().ResolveValue(exe_ctx, ast_context).UnaryNegate() == false) + { + if (error_ptr) + error_ptr->SetErrorString("Unary negate failed."); + return false; + } + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_not + // OPERANDS: none + // DESCRIPTION: pops the top stack entry, and pushes its bitwise + // complement + //---------------------------------------------------------------------- + case DW_OP_not: + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_not."); + return false; + } + else + { + if (stack.back().ResolveValue(exe_ctx, ast_context).OnesComplement() == false) + { + if (error_ptr) + error_ptr->SetErrorString("Logical NOT failed."); + return false; + } + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_or + // OPERANDS: none + // DESCRIPTION: pops the top two stack entries, performs a bitwise or + // operation on the two, and pushes the result. + //---------------------------------------------------------------------- + case DW_OP_or: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_or."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) | tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_plus + // OPERANDS: none + // DESCRIPTION: pops the top two stack entries, adds them together, and + // pushes the result. + //---------------------------------------------------------------------- + case DW_OP_plus: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_plus."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) + tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_plus_uconst + // OPERANDS: none + // DESCRIPTION: pops the top stack entry, adds it to the unsigned LEB128 + // constant operand and pushes the result. + //---------------------------------------------------------------------- + case DW_OP_plus_uconst: + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_plus_uconst."); + return false; + } + else + { + uint32_t uconst_value = opcodes.GetULEB128(&offset); + // Implicit conversion from a UINT to a Scalar... + stack.back().ResolveValue(exe_ctx, ast_context) += uconst_value; + if (!stack.back().ResolveValue(exe_ctx, ast_context).IsValid()) + { + if (error_ptr) + error_ptr->SetErrorString("DW_OP_plus_uconst failed."); + return false; + } + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_shl + // OPERANDS: none + // DESCRIPTION: pops the top two stack entries, shifts the former + // second entry left by the number of bits specified by the former top + // of the stack, and pushes the result. + //---------------------------------------------------------------------- + case DW_OP_shl: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shl."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) <<= tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_shr + // OPERANDS: none + // DESCRIPTION: pops the top two stack entries, shifts the former second + // entry right logically (filling with zero bits) by the number of bits + // specified by the former top of the stack, and pushes the result. + //---------------------------------------------------------------------- + case DW_OP_shr: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shr."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + if (stack.back().ResolveValue(exe_ctx, ast_context).ShiftRightLogical(tmp.ResolveValue(exe_ctx, ast_context)) == false) + { + if (error_ptr) + error_ptr->SetErrorString("DW_OP_shr failed."); + return false; + } + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_shra + // OPERANDS: none + // DESCRIPTION: pops the top two stack entries, shifts the former second + // entry right arithmetically (divide the magnitude by 2, keep the same + // sign for the result) by the number of bits specified by the former + // top of the stack, and pushes the result. + //---------------------------------------------------------------------- + case DW_OP_shra: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shra."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) >>= tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_xor + // OPERANDS: none + // DESCRIPTION: pops the top two stack entries, performs the bitwise + // exclusive-or operation on the two, and pushes the result. + //---------------------------------------------------------------------- + case DW_OP_xor: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_xor."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) ^ tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_skip + // OPERANDS: int16_t + // DESCRIPTION: An unconditional branch. Its single operand is a 2-byte + // signed integer constant. The 2-byte constant is the number of bytes + // of the DWARF expression to skip forward or backward from the current + // operation, beginning after the 2-byte constant. + //---------------------------------------------------------------------- + case DW_OP_skip: + { + int16_t skip_offset = (int16_t)opcodes.GetU16(&offset); + uint32_t new_offset = offset + skip_offset; + if (new_offset >= opcodes_offset && new_offset < end_offset) + offset = new_offset; + else + { + if (error_ptr) + error_ptr->SetErrorString("Invalid opcode offset in DW_OP_skip."); + return false; + } + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_bra + // OPERANDS: int16_t + // DESCRIPTION: A conditional branch. Its single operand is a 2-byte + // signed integer constant. This operation pops the top of stack. If + // the value popped is not the constant 0, the 2-byte constant operand + // is the number of bytes of the DWARF expression to skip forward or + // backward from the current operation, beginning after the 2-byte + // constant. + //---------------------------------------------------------------------- + case DW_OP_bra: + { + tmp = stack.back(); + stack.pop_back(); + int16_t bra_offset = (int16_t)opcodes.GetU16(&offset); + Scalar zero(0); + if (tmp.ResolveValue(exe_ctx, ast_context) != zero) + { + uint32_t new_offset = offset + bra_offset; + if (new_offset >= opcodes_offset && new_offset < end_offset) + offset = new_offset; + else + { + if (error_ptr) + error_ptr->SetErrorString("Invalid opcode offset in DW_OP_bra."); + return false; + } + } + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_eq + // OPERANDS: none + // DESCRIPTION: pops the top two stack values, compares using the + // equals (==) operator. + // STACK RESULT: push the constant value 1 onto the stack if the result + // of the operation is true or the constant value 0 if the result of the + // operation is false. + //---------------------------------------------------------------------- + case DW_OP_eq: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_eq."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) == tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_ge + // OPERANDS: none + // DESCRIPTION: pops the top two stack values, compares using the + // greater than or equal to (>=) operator. + // STACK RESULT: push the constant value 1 onto the stack if the result + // of the operation is true or the constant value 0 if the result of the + // operation is false. + //---------------------------------------------------------------------- + case DW_OP_ge: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_ge."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) >= tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_gt + // OPERANDS: none + // DESCRIPTION: pops the top two stack values, compares using the + // greater than (>) operator. + // STACK RESULT: push the constant value 1 onto the stack if the result + // of the operation is true or the constant value 0 if the result of the + // operation is false. + //---------------------------------------------------------------------- + case DW_OP_gt: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_gt."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) > tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_le + // OPERANDS: none + // DESCRIPTION: pops the top two stack values, compares using the + // less than or equal to (<=) operator. + // STACK RESULT: push the constant value 1 onto the stack if the result + // of the operation is true or the constant value 0 if the result of the + // operation is false. + //---------------------------------------------------------------------- + case DW_OP_le: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_le."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) <= tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_lt + // OPERANDS: none + // DESCRIPTION: pops the top two stack values, compares using the + // less than (<) operator. + // STACK RESULT: push the constant value 1 onto the stack if the result + // of the operation is true or the constant value 0 if the result of the + // operation is false. + //---------------------------------------------------------------------- + case DW_OP_lt: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_lt."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) < tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_ne + // OPERANDS: none + // DESCRIPTION: pops the top two stack values, compares using the + // not equal (!=) operator. + // STACK RESULT: push the constant value 1 onto the stack if the result + // of the operation is true or the constant value 0 if the result of the + // operation is false. + //---------------------------------------------------------------------- + case DW_OP_ne: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_ne."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx, ast_context) = stack.back().ResolveValue(exe_ctx, ast_context) != tmp.ResolveValue(exe_ctx, ast_context); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_litn + // OPERANDS: none + // DESCRIPTION: encode the unsigned literal values from 0 through 31. + // STACK RESULT: push the unsigned literal constant value onto the top + // of the stack. + //---------------------------------------------------------------------- + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + stack.push_back(op - DW_OP_lit0); + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_regN + // OPERANDS: none + // DESCRIPTION: Push the value in register n on the top of the stack. + //---------------------------------------------------------------------- + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + { + reg_num = op - DW_OP_reg0; + + if (ReadRegisterValueAsScalar (exe_ctx, reg_kind, reg_num, error_ptr, tmp)) + stack.push_back(tmp); + else + return false; + } + break; + //---------------------------------------------------------------------- + // OPCODE: DW_OP_regx + // OPERANDS: + // ULEB128 literal operand that encodes the register. + // DESCRIPTION: Push the value in register on the top of the stack. + //---------------------------------------------------------------------- + case DW_OP_regx: + { + reg_num = opcodes.GetULEB128(&offset); + if (ReadRegisterValueAsScalar (exe_ctx, reg_kind, reg_num, error_ptr, tmp)) + stack.push_back(tmp); + else + return false; + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_bregN + // OPERANDS: + // SLEB128 offset from register N + // DESCRIPTION: Value is in memory at the address specified by register + // N plus an offset. + //---------------------------------------------------------------------- + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + { + reg_num = op - DW_OP_breg0; + + if (ReadRegisterValueAsScalar (exe_ctx, reg_kind, reg_num, error_ptr, tmp)) + { + int64_t breg_offset = opcodes.GetSLEB128(&offset); + tmp.ResolveValue(exe_ctx, ast_context) += (uint64_t)breg_offset; + stack.push_back(tmp); + stack.back().SetValueType (Value::eValueTypeLoadAddress); + } + else + return false; + } + break; + //---------------------------------------------------------------------- + // OPCODE: DW_OP_bregx + // OPERANDS: 2 + // ULEB128 literal operand that encodes the register. + // SLEB128 offset from register N + // DESCRIPTION: Value is in memory at the address specified by register + // N plus an offset. + //---------------------------------------------------------------------- + case DW_OP_bregx: + { + reg_num = opcodes.GetULEB128(&offset); + + if (ReadRegisterValueAsScalar (exe_ctx, reg_kind, reg_num, error_ptr, tmp)) + { + int64_t breg_offset = opcodes.GetSLEB128(&offset); + tmp.ResolveValue(exe_ctx, ast_context) += (uint64_t)breg_offset; + stack.push_back(tmp); + stack.back().SetValueType (Value::eValueTypeLoadAddress); + } + else + return false; + } + break; + + case DW_OP_fbreg: + if (exe_ctx && exe_ctx->frame) + { + Scalar value; + if (exe_ctx->frame->GetFrameBaseValue(value, error_ptr)) + { + int64_t fbreg_offset = opcodes.GetSLEB128(&offset); + value += fbreg_offset; + stack.push_back(value); + stack.back().SetValueType (Value::eValueTypeLoadAddress); + } + else + return false; + } + else + { + if (error_ptr) + error_ptr->SetErrorString ("Invalid stack frame in context for DW_OP_fbreg opcode."); + return false; + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_nop + // OPERANDS: none + // DESCRIPTION: A place holder. It has no effect on the location stack + // or any of its values. + //---------------------------------------------------------------------- + case DW_OP_nop: + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_piece + // OPERANDS: 1 + // ULEB128: byte size of the piece + // DESCRIPTION: The operand describes the size in bytes of the piece of + // the object referenced by the DWARF expression whose result is at the + // top of the stack. If the piece is located in a register, but does not + // occupy the entire register, the placement of the piece within that + // register is defined by the ABI. + // + // Many compilers store a single variable in sets of registers, or store + // a variable partially in memory and partially in registers. + // DW_OP_piece provides a way of describing how large a part of a + // variable a particular DWARF expression refers to. + //---------------------------------------------------------------------- + case DW_OP_piece: + if (error_ptr) + error_ptr->SetErrorString ("Unimplemented opcode DW_OP_piece."); + return false; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_push_object_address + // OPERANDS: none + // DESCRIPTION: Pushes the address of the object currently being + // evaluated as part of evaluation of a user presented expression. + // This object may correspond to an independent variable described by + // its own DIE or it may be a component of an array, structure, or class + // whose address has been dynamically determined by an earlier step + // during user expression evaluation. + //---------------------------------------------------------------------- + case DW_OP_push_object_address: + if (error_ptr) + error_ptr->SetErrorString ("Unimplemented opcode DW_OP_push_object_address."); + return false; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_call2 + // OPERANDS: + // uint16_t compile unit relative offset of a DIE + // DESCRIPTION: Performs subroutine calls during evaluation + // of a DWARF expression. The operand is the 2-byte unsigned offset + // of a debugging information entry in the current compilation unit. + // + // Operand interpretation is exactly like that for DW_FORM_ref2. + // + // This operation transfers control of DWARF expression evaluation + // to the DW_AT_location attribute of the referenced DIE. If there is + // no such attribute, then there is no effect. Execution of the DWARF + // expression of a DW_AT_location attribute may add to and/or remove from + // values on the stack. Execution returns to the point following the call + // when the end of the attribute is reached. Values on the stack at the + // time of the call may be used as parameters by the called expression + // and values left on the stack by the called expression may be used as + // return values by prior agreement between the calling and called + // expressions. + //---------------------------------------------------------------------- + case DW_OP_call2: + if (error_ptr) + error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call2."); + return false; + //---------------------------------------------------------------------- + // OPCODE: DW_OP_call4 + // OPERANDS: 1 + // uint32_t compile unit relative offset of a DIE + // DESCRIPTION: Performs a subroutine call during evaluation of a DWARF + // expression. For DW_OP_call4, the operand is a 4-byte unsigned offset + // of a debugging information entry in the current compilation unit. + // + // Operand interpretation DW_OP_call4 is exactly like that for + // DW_FORM_ref4. + // + // This operation transfers control of DWARF expression evaluation + // to the DW_AT_location attribute of the referenced DIE. If there is + // no such attribute, then there is no effect. Execution of the DWARF + // expression of a DW_AT_location attribute may add to and/or remove from + // values on the stack. Execution returns to the point following the call + // when the end of the attribute is reached. Values on the stack at the + // time of the call may be used as parameters by the called expression + // and values left on the stack by the called expression may be used as + // return values by prior agreement between the calling and called + // expressions. + //---------------------------------------------------------------------- + case DW_OP_call4: + if (error_ptr) + error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call4."); + return false; + + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_call_ref + // OPERANDS: + // uint32_t absolute DIE offset for 32-bit DWARF or a uint64_t + // absolute DIE offset for 64 bit DWARF. + // DESCRIPTION: Performs a subroutine call during evaluation of a DWARF + // expression. Takes a single operand. In the 32-bit DWARF format, the + // operand is a 4-byte unsigned value; in the 64-bit DWARF format, it + // is an 8-byte unsigned value. The operand is used as the offset of a + // debugging information entry in a .debug_info section which may be + // contained in a shared object for executable other than that + // containing the operator. For references from one shared object or + // executable to another, the relocation must be performed by the + // consumer. + // + // Operand interpretation of DW_OP_call_ref is exactly like that for + // DW_FORM_ref_addr. + // + // This operation transfers control of DWARF expression evaluation + // to the DW_AT_location attribute of the referenced DIE. If there is + // no such attribute, then there is no effect. Execution of the DWARF + // expression of a DW_AT_location attribute may add to and/or remove from + // values on the stack. Execution returns to the point following the call + // when the end of the attribute is reached. Values on the stack at the + // time of the call may be used as parameters by the called expression + // and values left on the stack by the called expression may be used as + // return values by prior agreement between the calling and called + // expressions. + //---------------------------------------------------------------------- + case DW_OP_call_ref: + if (error_ptr) + error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call_ref."); + return false; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_array_ref + // OPERANDS: none + // DESCRIPTION: Pops a value off the stack and uses it as the array + // index. Pops a second value off the stack and uses it as the array + // itself. Pushes a value onto the stack representing the element of + // the array specified by the index. + //---------------------------------------------------------------------- + case DW_OP_APPLE_array_ref: + { + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_APPLE_array_ref."); + return false; + } + + Value index_val = stack.back(); + stack.pop_back(); + Value array_val = stack.back(); + stack.pop_back(); + + Scalar &index_scalar = index_val.ResolveValue(exe_ctx, ast_context); + int64_t index = index_scalar.SLongLong(LONG_LONG_MAX); + + if (index == LONG_LONG_MAX) + { + if (error_ptr) + error_ptr->SetErrorString("Invalid array index."); + return false; + } + + if (array_val.GetContextType() != Value::eContextTypeOpaqueClangQualType) + { + if (error_ptr) + error_ptr->SetErrorString("Arrays without Clang types are unhandled at this time."); + return false; + } + + if (array_val.GetValueType() != Value::eValueTypeLoadAddress && + array_val.GetValueType() != Value::eValueTypeHostAddress) + { + if (error_ptr) + error_ptr->SetErrorString("Array must be stored in memory."); + return false; + } + + void *array_type = array_val.GetOpaqueClangQualType(); + + void *member_type; + uint64_t size = 0; + + if ((!ClangASTContext::IsPointerType(array_type, &member_type)) && + (!ClangASTContext::IsArrayType(array_type, &member_type, &size))) + { + if (error_ptr) + error_ptr->SetErrorString("Array reference from something that is neither a pointer nor an array."); + return false; + } + + if (size && (index >= size || index < 0)) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("Out of bounds array access. %lld is not in [0, %llu]", index, size); + return false; + } + + uint64_t member_bit_size = ClangASTContext::GetTypeBitSize(ast_context, member_type); + uint64_t member_bit_align = ClangASTContext::GetTypeBitAlign(ast_context, member_type); + uint64_t member_bit_incr = ((member_bit_size + member_bit_align - 1) / member_bit_align) * member_bit_align; + if (member_bit_incr % 8) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat("Array increment is not byte aligned", index, size); + return false; + } + int64_t member_offset = (int64_t)(member_bit_incr / 8) * index; + + Value member; + + member.SetContext(Value::eContextTypeOpaqueClangQualType, member_type); + member.SetValueType(array_val.GetValueType()); + + addr_t array_base = (addr_t)array_val.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + addr_t member_loc = array_base + member_offset; + member.GetScalar() = (uint64_t)member_loc; + + stack.push_back(member); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_uninit + // OPERANDS: none + // DESCRIPTION: Lets us know that the value is currently not initialized + //---------------------------------------------------------------------- + case DW_OP_APPLE_uninit: + //return eResultTypeErrorUninitialized; + break; // Ignore this as we have seen cases where this value is incorrectly added + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_assign + // OPERANDS: none + // DESCRIPTION: Pops a value off of the stack and assigns it to the next + // item on the stack which must be something assignable (inferior + // Variable, inferior Type with address, inferior register, or + // expression local variable. + //---------------------------------------------------------------------- + case DW_OP_APPLE_assign: + if (stack.size() < 2) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_APPLE_assign."); + return false; + } + else + { + tmp = stack.back(); + stack.pop_back(); + Value::ContextType context_type = stack.back().GetContextType(); + StreamString new_value(Stream::eBinary, 4, eByteOrderHost); + switch (context_type) + { + case Value::eContextTypeOpaqueClangQualType: + { + void *clang_type = stack.back().GetOpaqueClangQualType(); + + if (ClangASTContext::IsAggregateType (clang_type)) + { + Value::ValueType source_value_type = tmp.GetValueType(); + Value::ValueType target_value_type = stack.back().GetValueType(); + + addr_t source_addr = (addr_t)tmp.GetScalar().ULongLong(); + addr_t target_addr = (addr_t)stack.back().GetScalar().ULongLong(); + + size_t byte_size = (ClangASTContext::GetTypeBitSize(ast_context, clang_type) + 7) / 8; + + switch (source_value_type) + { + case Value::eValueTypeLoadAddress: + switch (target_value_type) + { + case Value::eValueTypeLoadAddress: + { + DataBufferHeap data; + data.SetByteSize(byte_size); + + Error error; + if (exe_ctx->process->ReadMemory (source_addr, data.GetBytes(), byte_size, error) != byte_size) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("Couldn't read a composite type from the target: %s", error.AsCString()); + return false; + } + + if (exe_ctx->process->WriteMemory (target_addr, data.GetBytes(), byte_size, error) != byte_size) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("Couldn't write a composite type to the target: %s", error.AsCString()); + return false; + } + } + break; + case Value::eValueTypeHostAddress: + if (exe_ctx->process->GetByteOrder() != Host::GetByteOrder()) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("Copy of composite types between incompatible byte orders is unimplemented"); + return false; + } + else + { + Error error; + if (exe_ctx->process->ReadMemory (source_addr, (uint8_t*)target_addr, byte_size, error) != byte_size) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("Couldn't read a composite type from the target: %s", error.AsCString()); + return false; + } + } + break; + default: + return false; + } + break; + case Value::eValueTypeHostAddress: + switch (target_value_type) + { + case Value::eValueTypeLoadAddress: + if (exe_ctx->process->GetByteOrder() != Host::GetByteOrder()) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("Copy of composite types between incompatible byte orders is unimplemented"); + return false; + } + else + { + Error error; + if (exe_ctx->process->WriteMemory (target_addr, (uint8_t*)source_addr, byte_size, error) != byte_size) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("Couldn't write a composite type to the target: %s", error.AsCString()); + return false; + } + } + case Value::eValueTypeHostAddress: + memcpy ((uint8_t*)target_addr, (uint8_t*)source_addr, byte_size); + break; + default: + return false; + } + } + } + else + { + if (!Type::SetValueFromScalar(ast_context, + clang_type, + tmp.ResolveValue(exe_ctx, ast_context), + new_value)) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("Couldn't extract a value from an integral type.\n"); + return false; + } + + Value::ValueType value_type = stack.back().GetValueType(); + + switch (value_type) + { + case Value::eValueTypeLoadAddress: + case Value::eValueTypeHostAddress: + { + lldb::AddressType address_type = (value_type == Value::eValueTypeLoadAddress ? eAddressTypeLoad : eAddressTypeHost); + lldb::addr_t addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + if (!Type::WriteToMemory (exe_ctx, + ast_context, + clang_type, + addr, + address_type, + new_value)) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("Failed to write value to memory at 0x%llx.\n", addr); + return false; + } + } + break; + + default: + break; + } + } + } + break; + + default: + if (error_ptr) + error_ptr->SetErrorString ("Assign failed."); + return false; + } + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_address_of + // OPERANDS: none + // DESCRIPTION: Pops a value off of the stack and pushed its address. + // The top item on the stack must be a variable, or already be a memory + // location. + //---------------------------------------------------------------------- + case DW_OP_APPLE_address_of: + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_APPLE_address_of."); + return false; + } + else + { + Value::ValueType value_type = stack.back().GetValueType(); + switch (value_type) + { + default: + case Value::eValueTypeScalar: // raw scalar value + if (error_ptr) + error_ptr->SetErrorString("Top stack item isn't a memory based object."); + return false; + + case Value::eValueTypeLoadAddress: // load address value + case Value::eValueTypeFileAddress: // file address value + case Value::eValueTypeHostAddress: // host address value (for memory in the process that is using liblldb) + // Taking the address of an object reduces it to the address + // of the value and removes any extra context it had. + //stack.back().SetValueType(Value::eValueTypeScalar); + stack.back().ClearContext(); + break; + } + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_value_of + // OPERANDS: none + // DESCRIPTION: Pops a value off of the stack and pushed its value. + // The top item on the stack must be a variable, expression variable. + //---------------------------------------------------------------------- + case DW_OP_APPLE_value_of: + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 items for DW_OP_APPLE_value_of."); + return false; + } + else if (!stack.back().ValueOf(exe_ctx, ast_context)) + { + if (error_ptr) + error_ptr->SetErrorString ("Top stack item isn't a valid candidate for DW_OP_APPLE_value_of."); + return false; + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_deref_type + // OPERANDS: none + // DESCRIPTION: gets the value pointed to by the top stack item + //---------------------------------------------------------------------- + case DW_OP_APPLE_deref_type: + { + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 items for DW_OP_APPLE_deref_type."); + return false; + } + + tmp = stack.back(); + stack.pop_back(); + + if (tmp.GetContextType() != Value::eContextTypeOpaqueClangQualType) + { + if (error_ptr) + error_ptr->SetErrorString("Item at top of expression stack must have a Clang type"); + return false; + } + + void *ptr_type = tmp.GetOpaqueClangQualType(); + void *target_type; + + if (!ClangASTContext::IsPointerType(ptr_type, &target_type)) + { + if (error_ptr) + error_ptr->SetErrorString("Dereferencing a non-pointer type"); + return false; + } + + // TODO do we want all pointers to be dereferenced as load addresses? + Value::ValueType value_type = tmp.GetValueType(); + + tmp.ResolveValue(exe_ctx, ast_context); + + tmp.SetValueType(value_type); + tmp.SetContext(Value::eContextTypeOpaqueClangQualType, target_type); + + stack.push_back(tmp); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_expr_local + // OPERANDS: ULEB128 + // DESCRIPTION: pushes the expression local variable index onto the + // stack and set the appropriate context so we know the stack item is + // an expression local variable index. + //---------------------------------------------------------------------- + case DW_OP_APPLE_expr_local: + { + uint32_t idx = opcodes.GetULEB128(&offset); + if (expr_locals == NULL) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("DW_OP_APPLE_expr_local(%u) opcode encountered with no local variable list.\n", idx); + return false; + } + Value *expr_local_variable = expr_locals->GetVariableAtIndex(idx); + if (expr_local_variable == NULL) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("DW_OP_APPLE_expr_local(%u) with invalid index %u.\n", idx, idx); + return false; + } + Value *proxy = expr_local_variable->CreateProxy(); + stack.push_back(*proxy); + delete proxy; + //stack.back().SetContext (Value::eContextTypeOpaqueClangQualType, expr_local_variable->GetOpaqueClangQualType()); + } + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_extern + // OPERANDS: ULEB128 + // DESCRIPTION: pushes a proxy for the extern object index onto the + // stack. + //---------------------------------------------------------------------- + case DW_OP_APPLE_extern: + { + uint32_t idx = opcodes.GetULEB128(&offset); + if (!decl_map) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("DW_OP_APPLE_extern(%u) opcode encountered with no decl map.\n", idx); + return false; + } + Value *extern_var = decl_map->GetValueForIndex(idx); + if (!extern_var) + { + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("DW_OP_APPLE_extern(%u) with invalid index %u.\n", idx, idx); + return false; + } + Value *proxy = extern_var->CreateProxy(); + stack.push_back(*proxy); + delete proxy; + } + break; + + case DW_OP_APPLE_scalar_cast: + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_APPLE_scalar_cast."); + return false; + } + else + { + // Simple scalar cast + if (!stack.back().ResolveValue(exe_ctx, ast_context).Cast((Scalar::Type)opcodes.GetU8(&offset))) + { + if (error_ptr) + error_ptr->SetErrorString("Cast failed."); + return false; + } + } + break; + + + case DW_OP_APPLE_clang_cast: + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_APPLE_clang_cast."); + return false; + } + else + { + void *clang_type = (void *)opcodes.GetMaxU64(&offset, sizeof(void*)); + stack.back().SetContext (Value::eContextTypeOpaqueClangQualType, clang_type); + } + break; + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_constf + // OPERANDS: 1 byte float length, followed by that many bytes containing + // the constant float data. + // DESCRIPTION: Push a float value onto the expression stack. + //---------------------------------------------------------------------- + case DW_OP_APPLE_constf: // 0xF6 - 1 byte float size, followed by constant float data + { + uint8_t float_length = opcodes.GetU8(&offset); + if (sizeof(float) == float_length) + tmp.ResolveValue(exe_ctx, ast_context) = opcodes.GetFloat (&offset); + else if (sizeof(double) == float_length) + tmp.ResolveValue(exe_ctx, ast_context) = opcodes.GetDouble (&offset); + else if (sizeof(long double) == float_length) + tmp.ResolveValue(exe_ctx, ast_context) = opcodes.GetLongDouble (&offset); + else + { + StreamString new_value; + opcodes.Dump(&new_value, offset, eFormatBytes, 1, float_length, UINT32_MAX, DW_INVALID_ADDRESS, 0, 0); + + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("DW_OP_APPLE_constf(<%u> %s) unsupported float size.\n", float_length, new_value.GetData()); + return false; + } + tmp.SetValueType(Value::eValueTypeScalar); + tmp.ClearContext(); + stack.push_back(tmp); + } + break; + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_clear + // OPERANDS: none + // DESCRIPTION: Clears the expression stack. + //---------------------------------------------------------------------- + case DW_OP_APPLE_clear: + stack.clear(); + break; + + //---------------------------------------------------------------------- + // OPCODE: DW_OP_APPLE_error + // OPERANDS: none + // DESCRIPTION: Pops a value off of the stack and pushed its value. + // The top item on the stack must be a variable, expression variable. + //---------------------------------------------------------------------- + case DW_OP_APPLE_error: // 0xFF - Stops expression evaluation and returns an error (no args) + if (error_ptr) + error_ptr->SetErrorString ("Generic error."); + return false; + } + } + + if (stack.empty()) + { + if (error_ptr) + error_ptr->SetErrorString ("Stack empty after evaluation."); + return false; + } + else if (log) + { + log->Printf("\n"); + size_t count = stack.size(); + for (size_t i=0; i<count; ++i) + { + StreamString new_value; + new_value.Printf("[%zu]", i); + stack[i].Dump(&new_value); + log->Printf("%s", new_value.GetData()); + } + } + + result = stack.back(); + return true; // Return true on success +} + diff --git a/lldb/source/Expression/RecordingMemoryManager.cpp b/lldb/source/Expression/RecordingMemoryManager.cpp new file mode 100644 index 00000000000..9f732b6c976 --- /dev/null +++ b/lldb/source/Expression/RecordingMemoryManager.cpp @@ -0,0 +1,131 @@ +//===-- RecordingMemoryManager.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define NO_RTTI +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Expression/RecordingMemoryManager.h" + +using namespace lldb_private; + +RecordingMemoryManager::RecordingMemoryManager () : + llvm::JITMemoryManager(), + m_default_mm_ap (llvm::JITMemoryManager::CreateDefaultMemManager()) +{ +} + +RecordingMemoryManager::~RecordingMemoryManager () +{ +} + +void +RecordingMemoryManager::setMemoryWritable () +{ + m_default_mm_ap->setMemoryWritable(); +} + +void +RecordingMemoryManager::setMemoryExecutable () +{ + m_default_mm_ap->setMemoryExecutable(); +} + + +uint8_t * +RecordingMemoryManager::startFunctionBody(const llvm::Function *F, + uintptr_t &ActualSize) +{ + uint8_t *return_value = m_default_mm_ap->startFunctionBody(F, ActualSize); + return return_value; +} + +uint8_t * +RecordingMemoryManager::allocateStub(const llvm::GlobalValue* F, unsigned StubSize, + unsigned Alignment) +{ + uint8_t *return_value = m_default_mm_ap->allocateStub(F, StubSize, Alignment); + m_stubs.insert (std::pair<uint8_t *,unsigned>(return_value, StubSize)); + return return_value; +} + +void +RecordingMemoryManager::endFunctionBody(const llvm::Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd) +{ + m_default_mm_ap->endFunctionBody(F, FunctionStart, FunctionEnd); + m_functions.insert(std::pair<uint8_t *, uint8_t *>(FunctionStart, FunctionEnd)); +} + +uint8_t * +RecordingMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) +{ + uint8_t *return_value = m_default_mm_ap->allocateSpace(Size, Alignment); + m_spaceBlocks.insert (std::pair<uint8_t *, intptr_t>(return_value, Size)); + return return_value; +} + +uint8_t * +RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) +{ + uint8_t *return_value = m_default_mm_ap->allocateGlobal(Size, Alignment); + m_globals.insert (std::pair<uint8_t *, uintptr_t>(return_value, Size)); + return return_value; +} + +void +RecordingMemoryManager::deallocateFunctionBody(void *Body) +{ + m_default_mm_ap->deallocateFunctionBody(Body); +} + +uint8_t* +RecordingMemoryManager::startExceptionTable(const llvm::Function* F, + uintptr_t &ActualSize) +{ + uint8_t *return_value = m_default_mm_ap->startExceptionTable(F, ActualSize); + return return_value; +} + +void +RecordingMemoryManager::endExceptionTable(const llvm::Function *F, uint8_t *TableStart, + uint8_t *TableEnd, uint8_t* FrameRegister) +{ + m_default_mm_ap->endExceptionTable(F, TableStart, TableEnd, FrameRegister); + m_exception_tables.insert (std::pair<uint8_t *, uint8_t *>(TableStart, TableEnd)); +} + +void +RecordingMemoryManager::deallocateExceptionTable(void *ET) +{ + m_default_mm_ap->deallocateExceptionTable (ET); +} + +lldb::addr_t +RecordingMemoryManager::GetRemoteAddressForLocal (lldb::addr_t local_address) +{ + std::vector<LocalToRemoteAddressRange>::iterator pos, end = m_address_map.end(); + for (pos = m_address_map.begin(); pos < end; pos++) + { + lldb::addr_t lstart = (*pos).m_local_start; + if (local_address >= lstart && local_address < lstart + (*pos).m_size) + { + return (*pos).m_remote_start + (local_address - lstart); + } + } + return LLDB_INVALID_ADDRESS; +} + +void +RecordingMemoryManager::AddToLocalToRemoteMap (lldb::addr_t lstart, size_t size, lldb::addr_t rstart) +{ + m_address_map.push_back (LocalToRemoteAddressRange(lstart, size, rstart)); +} + |