| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 1 | //===-- ClangExpressionParser.cpp -------------------------------*- C++ -*-===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 |  | 
|  | 10 | #include "lldb/Expression/ClangExpressionParser.h" | 
|  | 11 |  | 
|  | 12 | #include "lldb/Core/ArchSpec.h" | 
|  | 13 | #include "lldb/Core/DataBufferHeap.h" | 
|  | 14 | #include "lldb/Core/Disassembler.h" | 
|  | 15 | #include "lldb/Core/Stream.h" | 
| Sean Callanan | f18d91c | 2010-09-01 00:58:00 +0000 | [diff] [blame] | 16 | #include "lldb/Core/StreamString.h" | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 17 | #include "lldb/Expression/ClangASTSource.h" | 
|  | 18 | #include "lldb/Expression/ClangExpression.h" | 
| Sean Callanan | f18d91c | 2010-09-01 00:58:00 +0000 | [diff] [blame] | 19 | #include "lldb/Expression/IRDynamicChecks.h" | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 20 | #include "lldb/Expression/IRForTarget.h" | 
|  | 21 | #include "lldb/Expression/IRToDWARF.h" | 
|  | 22 | #include "lldb/Expression/RecordingMemoryManager.h" | 
|  | 23 | #include "lldb/Target/ExecutionContext.h" | 
|  | 24 | #include "lldb/Target/Process.h" | 
|  | 25 | #include "lldb/Target/Target.h" | 
|  | 26 |  | 
|  | 27 | #include "clang/AST/ASTContext.h" | 
|  | 28 | #include "clang/AST/ExternalASTSource.h" | 
|  | 29 | #include "clang/Basic/FileManager.h" | 
|  | 30 | #include "clang/Basic/TargetInfo.h" | 
|  | 31 | #include "clang/Basic/Version.h" | 
|  | 32 | #include "clang/Checker/FrontendActions.h" | 
|  | 33 | #include "clang/CodeGen/CodeGenAction.h" | 
|  | 34 | #include "clang/CodeGen/ModuleBuilder.h" | 
|  | 35 | #include "clang/Driver/CC1Options.h" | 
|  | 36 | #include "clang/Driver/OptTable.h" | 
|  | 37 | #include "clang/Frontend/CompilerInstance.h" | 
|  | 38 | #include "clang/Frontend/CompilerInvocation.h" | 
|  | 39 | #include "clang/Frontend/FrontendActions.h" | 
|  | 40 | #include "clang/Frontend/FrontendDiagnostic.h" | 
|  | 41 | #include "clang/Frontend/FrontendPluginRegistry.h" | 
|  | 42 | #include "clang/Frontend/TextDiagnosticBuffer.h" | 
|  | 43 | #include "clang/Frontend/TextDiagnosticPrinter.h" | 
|  | 44 | #include "clang/Frontend/VerifyDiagnosticsClient.h" | 
|  | 45 | #include "clang/Lex/Preprocessor.h" | 
| Sean Callanan | 47a5c4c | 2010-09-23 03:01:22 +0000 | [diff] [blame] | 46 | #include "clang/Parse/ParseAST.h" | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 47 | #include "clang/Rewrite/FrontendActions.h" | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 48 | #include "clang/Sema/SemaConsumer.h" | 
|  | 49 |  | 
|  | 50 | #include "llvm/ADT/StringRef.h" | 
|  | 51 | #include "llvm/ExecutionEngine/ExecutionEngine.h" | 
|  | 52 | #include "llvm/ExecutionEngine/JIT.h" | 
|  | 53 | #include "llvm/Module.h" | 
|  | 54 | #include "llvm/LLVMContext.h" | 
|  | 55 | #include "llvm/Support/ErrorHandling.h" | 
|  | 56 | #include "llvm/Support/MemoryBuffer.h" | 
| Greg Clayton | 22defe8 | 2010-12-02 23:20:03 +0000 | [diff] [blame] | 57 | #include "llvm/Support/DynamicLibrary.h" | 
|  | 58 | #include "llvm/Support/Host.h" | 
|  | 59 | #include "llvm/Support/Signals.h" | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 60 | #include "llvm/Target/TargetRegistry.h" | 
|  | 61 | #include "llvm/Target/TargetSelect.h" | 
|  | 62 |  | 
|  | 63 | using namespace clang; | 
|  | 64 | using namespace llvm; | 
|  | 65 | using namespace lldb_private; | 
|  | 66 |  | 
|  | 67 | //===----------------------------------------------------------------------===// | 
|  | 68 | // Utility Methods for Clang | 
|  | 69 | //===----------------------------------------------------------------------===// | 
|  | 70 |  | 
|  | 71 | std::string GetBuiltinIncludePath(const char *Argv0) { | 
|  | 72 | llvm::sys::Path P = | 
|  | 73 | llvm::sys::Path::GetMainExecutable(Argv0, | 
|  | 74 | (void*)(intptr_t) GetBuiltinIncludePath); | 
|  | 75 |  | 
|  | 76 | if (!P.isEmpty()) { | 
|  | 77 | P.eraseComponent();  // Remove /clang from foo/bin/clang | 
|  | 78 | P.eraseComponent();  // Remove /bin   from foo/bin | 
|  | 79 |  | 
|  | 80 | // Get foo/lib/clang/<version>/include | 
|  | 81 | P.appendComponent("lib"); | 
|  | 82 | P.appendComponent("clang"); | 
|  | 83 | P.appendComponent(CLANG_VERSION_STRING); | 
|  | 84 | P.appendComponent("include"); | 
|  | 85 | } | 
|  | 86 |  | 
|  | 87 | return P.str(); | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 |  | 
|  | 91 | //===----------------------------------------------------------------------===// | 
|  | 92 | // Main driver for Clang | 
|  | 93 | //===----------------------------------------------------------------------===// | 
|  | 94 |  | 
|  | 95 | static void LLVMErrorHandler(void *UserData, const std::string &Message) { | 
|  | 96 | Diagnostic &Diags = *static_cast<Diagnostic*>(UserData); | 
|  | 97 |  | 
|  | 98 | Diags.Report(diag::err_fe_error_backend) << Message; | 
|  | 99 |  | 
|  | 100 | // We cannot recover from llvm errors. | 
|  | 101 | exit(1); | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { | 
|  | 105 | using namespace clang::frontend; | 
|  | 106 |  | 
|  | 107 | switch (CI.getFrontendOpts().ProgramAction) { | 
|  | 108 | default: | 
|  | 109 | llvm_unreachable("Invalid program action!"); | 
|  | 110 |  | 
|  | 111 | case ASTDump:                return new ASTDumpAction(); | 
|  | 112 | case ASTPrint:               return new ASTPrintAction(); | 
|  | 113 | case ASTPrintXML:            return new ASTPrintXMLAction(); | 
|  | 114 | case ASTView:                return new ASTViewAction(); | 
|  | 115 | case BoostCon:               return new BoostConAction(); | 
|  | 116 | case DumpRawTokens:          return new DumpRawTokensAction(); | 
|  | 117 | case DumpTokens:             return new DumpTokensAction(); | 
|  | 118 | case EmitAssembly:           return new EmitAssemblyAction(); | 
|  | 119 | case EmitBC:                 return new EmitBCAction(); | 
|  | 120 | case EmitHTML:               return new HTMLPrintAction(); | 
|  | 121 | case EmitLLVM:               return new EmitLLVMAction(); | 
|  | 122 | case EmitLLVMOnly:           return new EmitLLVMOnlyAction(); | 
|  | 123 | case EmitCodeGenOnly:        return new EmitCodeGenOnlyAction(); | 
|  | 124 | case EmitObj:                return new EmitObjAction(); | 
|  | 125 | case FixIt:                  return new FixItAction(); | 
|  | 126 | case GeneratePCH:            return new GeneratePCHAction(); | 
|  | 127 | case GeneratePTH:            return new GeneratePTHAction(); | 
|  | 128 | case InheritanceView:        return new InheritanceViewAction(); | 
|  | 129 | case InitOnly:               return new InitOnlyAction(); | 
|  | 130 | case ParseSyntaxOnly:        return new SyntaxOnlyAction(); | 
|  | 131 |  | 
|  | 132 | case PluginAction: { | 
|  | 133 | for (FrontendPluginRegistry::iterator it = | 
|  | 134 | FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); | 
|  | 135 | it != ie; ++it) { | 
|  | 136 | if (it->getName() == CI.getFrontendOpts().ActionName) { | 
|  | 137 | llvm::OwningPtr<PluginASTAction> P(it->instantiate()); | 
|  | 138 | if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs)) | 
|  | 139 | return 0; | 
|  | 140 | return P.take(); | 
|  | 141 | } | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) | 
|  | 145 | << CI.getFrontendOpts().ActionName; | 
|  | 146 | return 0; | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 | case PrintDeclContext:       return new DeclContextPrintAction(); | 
|  | 150 | case PrintPreamble:          return new PrintPreambleAction(); | 
|  | 151 | case PrintPreprocessedInput: return new PrintPreprocessedAction(); | 
|  | 152 | case RewriteMacros:          return new RewriteMacrosAction(); | 
|  | 153 | case RewriteObjC:            return new RewriteObjCAction(); | 
|  | 154 | case RewriteTest:            return new RewriteTestAction(); | 
|  | 155 | case RunAnalysis:            return new AnalysisAction(); | 
|  | 156 | case RunPreprocessorOnly:    return new PreprocessOnlyAction(); | 
|  | 157 | } | 
|  | 158 | } | 
|  | 159 |  | 
|  | 160 | static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { | 
|  | 161 | // Create the underlying action. | 
|  | 162 | FrontendAction *Act = CreateFrontendBaseAction(CI); | 
|  | 163 | if (!Act) | 
|  | 164 | return 0; | 
|  | 165 |  | 
|  | 166 | // If there are any AST files to merge, create a frontend action | 
|  | 167 | // adaptor to perform the merge. | 
|  | 168 | if (!CI.getFrontendOpts().ASTMergeFiles.empty()) | 
|  | 169 | Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0], | 
|  | 170 | CI.getFrontendOpts().ASTMergeFiles.size()); | 
|  | 171 |  | 
|  | 172 | return Act; | 
|  | 173 | } | 
|  | 174 |  | 
|  | 175 | //===----------------------------------------------------------------------===// | 
|  | 176 | // Implementation of ClangExpressionParser | 
|  | 177 | //===----------------------------------------------------------------------===// | 
|  | 178 |  | 
|  | 179 | ClangExpressionParser::ClangExpressionParser(const char *target_triple, | 
|  | 180 | ClangExpression &expr) : | 
|  | 181 | m_expr(expr), | 
|  | 182 | m_target_triple (), | 
|  | 183 | m_compiler (), | 
|  | 184 | m_code_generator (NULL), | 
|  | 185 | m_execution_engine (), | 
|  | 186 | m_jitted_functions () | 
|  | 187 | { | 
|  | 188 | // Initialize targets first, so that --version shows registered targets. | 
|  | 189 | static struct InitializeLLVM { | 
|  | 190 | InitializeLLVM() { | 
|  | 191 | llvm::InitializeAllTargets(); | 
|  | 192 | llvm::InitializeAllAsmPrinters(); | 
|  | 193 | } | 
|  | 194 | } InitializeLLVM; | 
|  | 195 |  | 
|  | 196 | if (target_triple && target_triple[0]) | 
|  | 197 | m_target_triple = target_triple; | 
|  | 198 | else | 
|  | 199 | m_target_triple = llvm::sys::getHostTriple(); | 
|  | 200 |  | 
|  | 201 | // 1. Create a new compiler instance. | 
|  | 202 | m_compiler.reset(new CompilerInstance()); | 
|  | 203 | m_compiler->setLLVMContext(new LLVMContext()); | 
|  | 204 |  | 
|  | 205 | // 2. Set options. | 
|  | 206 |  | 
|  | 207 | // Parse expressions as Objective C++ regardless of context. | 
|  | 208 | // Our hook into Clang's lookup mechanism only works in C++. | 
|  | 209 | m_compiler->getLangOpts().CPlusPlus = true; | 
| Greg Clayton | f51ed30 | 2011-01-15 01:32:14 +0000 | [diff] [blame^] | 210 |  | 
|  | 211 | // Setup objective C | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 212 | m_compiler->getLangOpts().ObjC1 = true; | 
| Greg Clayton | f51ed30 | 2011-01-15 01:32:14 +0000 | [diff] [blame^] | 213 | m_compiler->getLangOpts().ObjC2 = true; | 
|  | 214 | // We need to enable the fragile ABI for things target triples that | 
|  | 215 | // support it. | 
|  | 216 | //    m_compiler->getLangOpts().ObjCNonFragileABI = true;     // NOT i386 | 
|  | 217 | //    m_compiler->getLangOpts().ObjCNonFragileABI2 = true;    // NOT i386 | 
|  | 218 |  | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 219 | m_compiler->getLangOpts().ThreadsafeStatics = false; | 
|  | 220 | m_compiler->getLangOpts().AccessControl = false; // Debuggers get universal access | 
|  | 221 | m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name | 
|  | 222 |  | 
|  | 223 | // Set CodeGen options | 
|  | 224 | m_compiler->getCodeGenOpts().EmitDeclMetadata = true; | 
|  | 225 | m_compiler->getCodeGenOpts().InstrumentFunctions = false; | 
|  | 226 |  | 
|  | 227 | // Disable some warnings. | 
|  | 228 | m_compiler->getDiagnosticOpts().Warnings.push_back("no-unused-value"); | 
|  | 229 |  | 
|  | 230 | // Set the target triple. | 
|  | 231 | m_compiler->getTargetOpts().Triple = m_target_triple; | 
|  | 232 |  | 
|  | 233 | // 3. Set up various important bits of infrastructure. | 
|  | 234 | m_compiler->createDiagnostics(0, 0); | 
|  | 235 |  | 
|  | 236 | // Create the target instance. | 
|  | 237 | m_compiler->setTarget(TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(), | 
|  | 238 | m_compiler->getTargetOpts())); | 
|  | 239 |  | 
|  | 240 | assert (m_compiler->hasTarget()); | 
|  | 241 |  | 
|  | 242 | // Inform the target of the language options | 
|  | 243 | // | 
|  | 244 | // FIXME: We shouldn't need to do this, the target should be immutable once | 
|  | 245 | // created. This complexity should be lifted elsewhere. | 
|  | 246 | m_compiler->getTarget().setForcedLangOptions(m_compiler->getLangOpts()); | 
|  | 247 |  | 
|  | 248 | // 4. Set up the diagnostic buffer for reporting errors | 
|  | 249 |  | 
| Sean Callanan | 47a5c4c | 2010-09-23 03:01:22 +0000 | [diff] [blame] | 250 | m_compiler->getDiagnostics().setClient(new clang::TextDiagnosticBuffer); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 251 |  | 
|  | 252 | // 5. Set up the source management objects inside the compiler | 
|  | 253 |  | 
| Greg Clayton | 22defe8 | 2010-12-02 23:20:03 +0000 | [diff] [blame] | 254 | clang::FileSystemOptions file_system_options; | 
|  | 255 | m_file_manager.reset(new clang::FileManager(file_system_options)); | 
| Sean Callanan | 8a3b0a8 | 2010-11-18 02:56:27 +0000 | [diff] [blame] | 256 |  | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 257 | if (!m_compiler->hasSourceManager()) | 
| Greg Clayton | 22defe8 | 2010-12-02 23:20:03 +0000 | [diff] [blame] | 258 | m_compiler->createSourceManager(*m_file_manager.get()); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 259 |  | 
|  | 260 | m_compiler->createFileManager(); | 
|  | 261 | m_compiler->createPreprocessor(); | 
|  | 262 |  | 
|  | 263 | // 6. Most of this we get from the CompilerInstance, but we | 
|  | 264 | // also want to give the context an ExternalASTSource. | 
| Sean Callanan | ee8fc72 | 2010-11-19 20:20:02 +0000 | [diff] [blame] | 265 | m_selector_table.reset(new SelectorTable()); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 266 | m_builtin_context.reset(new Builtin::Context(m_compiler->getTarget())); | 
|  | 267 |  | 
|  | 268 | std::auto_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(), | 
|  | 269 | m_compiler->getSourceManager(), | 
|  | 270 | m_compiler->getTarget(), | 
|  | 271 | m_compiler->getPreprocessor().getIdentifierTable(), | 
| Sean Callanan | ee8fc72 | 2010-11-19 20:20:02 +0000 | [diff] [blame] | 272 | *m_selector_table.get(), | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 273 | *m_builtin_context.get(), | 
|  | 274 | 0)); | 
|  | 275 |  | 
|  | 276 | ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); | 
|  | 277 |  | 
|  | 278 | if (decl_map) | 
|  | 279 | { | 
|  | 280 | OwningPtr<clang::ExternalASTSource> ast_source(new ClangASTSource(*ast_context, *decl_map)); | 
|  | 281 | ast_context->setExternalSource(ast_source); | 
|  | 282 | } | 
|  | 283 |  | 
|  | 284 | m_compiler->setASTContext(ast_context.release()); | 
|  | 285 |  | 
| Greg Clayton | 8de27c7 | 2010-10-15 22:48:33 +0000 | [diff] [blame] | 286 | std::string module_name("$__lldb_module"); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 287 |  | 
|  | 288 | m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(), | 
|  | 289 | module_name, | 
|  | 290 | m_compiler->getCodeGenOpts(), | 
|  | 291 | m_compiler->getLLVMContext())); | 
|  | 292 | } | 
|  | 293 |  | 
|  | 294 | ClangExpressionParser::~ClangExpressionParser() | 
|  | 295 | { | 
|  | 296 | } | 
|  | 297 |  | 
|  | 298 | unsigned | 
|  | 299 | ClangExpressionParser::Parse (Stream &stream) | 
|  | 300 | { | 
| Sean Callanan | 47a5c4c | 2010-09-23 03:01:22 +0000 | [diff] [blame] | 301 | TextDiagnosticBuffer *diag_buf = static_cast<TextDiagnosticBuffer*>(m_compiler->getDiagnostics().getClient()); | 
|  | 302 |  | 
|  | 303 | diag_buf->FlushDiagnostics (m_compiler->getDiagnostics()); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 304 |  | 
|  | 305 | MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(m_expr.Text(), __FUNCTION__); | 
|  | 306 | FileID memory_buffer_file_id = m_compiler->getSourceManager().createMainFileIDForMemBuffer (memory_buffer); | 
|  | 307 |  | 
| Sean Callanan | 47a5c4c | 2010-09-23 03:01:22 +0000 | [diff] [blame] | 308 | diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor()); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 309 |  | 
|  | 310 | ASTConsumer *ast_transformer = m_expr.ASTTransformer(m_code_generator.get()); | 
|  | 311 |  | 
|  | 312 | if (ast_transformer) | 
|  | 313 | ParseAST(m_compiler->getPreprocessor(), ast_transformer, m_compiler->getASTContext()); | 
|  | 314 | else | 
|  | 315 | ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), m_compiler->getASTContext()); | 
|  | 316 |  | 
| Sean Callanan | 47a5c4c | 2010-09-23 03:01:22 +0000 | [diff] [blame] | 317 | diag_buf->EndSourceFile(); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 318 |  | 
|  | 319 | TextDiagnosticBuffer::const_iterator diag_iterator; | 
|  | 320 |  | 
|  | 321 | int num_errors = 0; | 
| Sean Callanan | 7617c29 | 2010-11-01 20:28:09 +0000 | [diff] [blame] | 322 |  | 
| Sean Callanan | 47a5c4c | 2010-09-23 03:01:22 +0000 | [diff] [blame] | 323 | for (diag_iterator = diag_buf->warn_begin(); | 
|  | 324 | diag_iterator != diag_buf->warn_end(); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 325 | ++diag_iterator) | 
|  | 326 | stream.Printf("warning: %s\n", (*diag_iterator).second.c_str()); | 
|  | 327 |  | 
|  | 328 | num_errors = 0; | 
|  | 329 |  | 
| Sean Callanan | 47a5c4c | 2010-09-23 03:01:22 +0000 | [diff] [blame] | 330 | for (diag_iterator = diag_buf->err_begin(); | 
|  | 331 | diag_iterator != diag_buf->err_end(); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 332 | ++diag_iterator) | 
|  | 333 | { | 
|  | 334 | num_errors++; | 
|  | 335 | stream.Printf("error: %s\n", (*diag_iterator).second.c_str()); | 
|  | 336 | } | 
|  | 337 |  | 
| Sean Callanan | 7617c29 | 2010-11-01 20:28:09 +0000 | [diff] [blame] | 338 | for (diag_iterator = diag_buf->note_begin(); | 
|  | 339 | diag_iterator != diag_buf->note_end(); | 
|  | 340 | ++diag_iterator) | 
|  | 341 | stream.Printf("note: %s\n", (*diag_iterator).second.c_str()); | 
|  | 342 |  | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 343 | return num_errors; | 
|  | 344 | } | 
|  | 345 |  | 
| Sean Callanan | 3c9c5eb | 2010-09-21 00:44:12 +0000 | [diff] [blame] | 346 | static bool FindFunctionInModule (std::string &mangled_name, | 
|  | 347 | llvm::Module *module, | 
|  | 348 | const char *orig_name) | 
|  | 349 | { | 
|  | 350 | for (llvm::Module::iterator fi = module->getFunctionList().begin(), fe = module->getFunctionList().end(); | 
|  | 351 | fi != fe; | 
|  | 352 | ++fi) | 
|  | 353 | { | 
|  | 354 | if (fi->getName().str().find(orig_name) != std::string::npos) | 
|  | 355 | { | 
|  | 356 | mangled_name = fi->getName().str(); | 
|  | 357 | return true; | 
|  | 358 | } | 
|  | 359 | } | 
|  | 360 |  | 
|  | 361 | return false; | 
|  | 362 | } | 
|  | 363 |  | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 364 | Error | 
|  | 365 | ClangExpressionParser::MakeDWARF () | 
|  | 366 | { | 
|  | 367 | Error err; | 
|  | 368 |  | 
|  | 369 | llvm::Module *module = m_code_generator->GetModule(); | 
|  | 370 |  | 
|  | 371 | if (!module) | 
|  | 372 | { | 
|  | 373 | err.SetErrorToGenericError(); | 
|  | 374 | err.SetErrorString("IR doesn't contain a module"); | 
|  | 375 | return err; | 
|  | 376 | } | 
|  | 377 |  | 
| Greg Clayton | 427f290 | 2010-12-14 02:59:59 +0000 | [diff] [blame] | 378 | ClangExpressionVariableList *local_variables = m_expr.LocalVariables(); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 379 | ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); | 
|  | 380 |  | 
|  | 381 | if (!local_variables) | 
|  | 382 | { | 
|  | 383 | err.SetErrorToGenericError(); | 
|  | 384 | err.SetErrorString("Can't convert an expression without a VariableList to DWARF"); | 
|  | 385 | return err; | 
|  | 386 | } | 
|  | 387 |  | 
|  | 388 | if (!decl_map) | 
|  | 389 | { | 
|  | 390 | err.SetErrorToGenericError(); | 
|  | 391 | err.SetErrorString("Can't convert an expression without a DeclMap to DWARF"); | 
|  | 392 | return err; | 
|  | 393 | } | 
|  | 394 |  | 
| Sean Callanan | 3c9c5eb | 2010-09-21 00:44:12 +0000 | [diff] [blame] | 395 | std::string function_name; | 
|  | 396 |  | 
|  | 397 | if (!FindFunctionInModule(function_name, module, m_expr.FunctionName())) | 
|  | 398 | { | 
|  | 399 | err.SetErrorToGenericError(); | 
|  | 400 | err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName()); | 
|  | 401 | return err; | 
|  | 402 | } | 
|  | 403 |  | 
|  | 404 | IRToDWARF ir_to_dwarf(*local_variables, decl_map, m_expr.DwarfOpcodeStream(), function_name.c_str()); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 405 |  | 
|  | 406 | if (!ir_to_dwarf.runOnModule(*module)) | 
|  | 407 | { | 
|  | 408 | err.SetErrorToGenericError(); | 
|  | 409 | err.SetErrorString("Couldn't convert the expression to DWARF"); | 
|  | 410 | return err; | 
|  | 411 | } | 
|  | 412 |  | 
|  | 413 | err.Clear(); | 
|  | 414 | return err; | 
|  | 415 | } | 
|  | 416 |  | 
|  | 417 | Error | 
| Sean Callanan | 830a903 | 2010-08-27 23:31:21 +0000 | [diff] [blame] | 418 | ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr, | 
|  | 419 | lldb::addr_t &func_end, | 
| Sean Callanan | 05a5a1b | 2010-12-16 03:17:46 +0000 | [diff] [blame] | 420 | ExecutionContext &exe_ctx, | 
|  | 421 | lldb::ClangExpressionVariableSP *const_result) | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 422 | { | 
| Greg Clayton | e005f2c | 2010-11-06 01:53:30 +0000 | [diff] [blame] | 423 | lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); | 
| Sean Callanan | 3c9c5eb | 2010-09-21 00:44:12 +0000 | [diff] [blame] | 424 |  | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 425 | Error err; | 
|  | 426 |  | 
|  | 427 | llvm::Module *module = m_code_generator->ReleaseModule(); | 
|  | 428 |  | 
|  | 429 | if (!module) | 
|  | 430 | { | 
|  | 431 | err.SetErrorToGenericError(); | 
|  | 432 | err.SetErrorString("IR doesn't contain a module"); | 
|  | 433 | return err; | 
|  | 434 | } | 
|  | 435 |  | 
| Sean Callanan | 3c9c5eb | 2010-09-21 00:44:12 +0000 | [diff] [blame] | 436 | // Find the actual name of the function (it's often mangled somehow) | 
|  | 437 |  | 
|  | 438 | std::string function_name; | 
|  | 439 |  | 
|  | 440 | if (!FindFunctionInModule(function_name, module, m_expr.FunctionName())) | 
|  | 441 | { | 
|  | 442 | err.SetErrorToGenericError(); | 
|  | 443 | err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName()); | 
|  | 444 | return err; | 
|  | 445 | } | 
|  | 446 | else | 
|  | 447 | { | 
|  | 448 | if(log) | 
|  | 449 | log->Printf("Found function %s for %s", function_name.c_str(), m_expr.FunctionName()); | 
|  | 450 | } | 
|  | 451 |  | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 452 | ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); // result can be NULL | 
|  | 453 |  | 
|  | 454 | if (decl_map) | 
|  | 455 | { | 
| Sean Callanan | e8a59a8 | 2010-09-13 21:34:21 +0000 | [diff] [blame] | 456 | IRForTarget ir_for_target(decl_map, | 
| Sean Callanan | e8a59a8 | 2010-09-13 21:34:21 +0000 | [diff] [blame] | 457 | m_expr.NeedsVariableResolution(), | 
| Sean Callanan | 05a5a1b | 2010-12-16 03:17:46 +0000 | [diff] [blame] | 458 | const_result, | 
| Sean Callanan | 3c9c5eb | 2010-09-21 00:44:12 +0000 | [diff] [blame] | 459 | function_name.c_str()); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 460 |  | 
|  | 461 | if (!ir_for_target.runOnModule(*module)) | 
|  | 462 | { | 
|  | 463 | err.SetErrorToGenericError(); | 
|  | 464 | err.SetErrorString("Couldn't convert the expression to DWARF"); | 
|  | 465 | return err; | 
|  | 466 | } | 
| Sean Callanan | f18d91c | 2010-09-01 00:58:00 +0000 | [diff] [blame] | 467 |  | 
| Jim Ingham | d168690 | 2010-10-14 23:45:03 +0000 | [diff] [blame] | 468 | if (m_expr.NeedsValidation() && exe_ctx.process->GetDynamicCheckers()) | 
| Sean Callanan | f18d91c | 2010-09-01 00:58:00 +0000 | [diff] [blame] | 469 | { | 
| Sean Callanan | 3c9c5eb | 2010-09-21 00:44:12 +0000 | [diff] [blame] | 470 | IRDynamicChecks ir_dynamic_checks(*exe_ctx.process->GetDynamicCheckers(), function_name.c_str()); | 
| Sean Callanan | e8a59a8 | 2010-09-13 21:34:21 +0000 | [diff] [blame] | 471 |  | 
|  | 472 | if (!ir_dynamic_checks.runOnModule(*module)) | 
|  | 473 | { | 
|  | 474 | err.SetErrorToGenericError(); | 
|  | 475 | err.SetErrorString("Couldn't add dynamic checks to the expression"); | 
|  | 476 | return err; | 
|  | 477 | } | 
|  | 478 | } | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 479 | } | 
|  | 480 |  | 
|  | 481 | m_jit_mm = new RecordingMemoryManager(); | 
|  | 482 |  | 
|  | 483 | std::string error_string; | 
| Sean Callanan | 9ac3a96 | 2010-11-02 23:20:00 +0000 | [diff] [blame] | 484 |  | 
| Sean Callanan | c2c6f77 | 2010-10-26 00:31:56 +0000 | [diff] [blame] | 485 | llvm::TargetMachine::setRelocationModel(llvm::Reloc::PIC_); | 
|  | 486 |  | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 487 | m_execution_engine.reset(llvm::ExecutionEngine::createJIT (module, | 
|  | 488 | &error_string, | 
|  | 489 | m_jit_mm, | 
| Sean Callanan | c2c6f77 | 2010-10-26 00:31:56 +0000 | [diff] [blame] | 490 | CodeGenOpt::Less, | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 491 | true, | 
|  | 492 | CodeModel::Small)); | 
| Sean Callanan | 9ac3a96 | 2010-11-02 23:20:00 +0000 | [diff] [blame] | 493 |  | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 494 | if (!m_execution_engine.get()) | 
|  | 495 | { | 
|  | 496 | err.SetErrorToGenericError(); | 
|  | 497 | err.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str()); | 
|  | 498 | return err; | 
|  | 499 | } | 
|  | 500 |  | 
|  | 501 | m_execution_engine->DisableLazyCompilation(); | 
|  | 502 |  | 
| Sean Callanan | 3c9c5eb | 2010-09-21 00:44:12 +0000 | [diff] [blame] | 503 | llvm::Function *function = module->getFunction (function_name.c_str()); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 504 |  | 
|  | 505 | // We don't actually need the function pointer here, this just forces it to get resolved. | 
|  | 506 |  | 
|  | 507 | void *fun_ptr = m_execution_engine->getPointerToFunction(function); | 
|  | 508 |  | 
|  | 509 | // Errors usually cause failures in the JIT, but if we're lucky we get here. | 
|  | 510 |  | 
|  | 511 | if (!fun_ptr) | 
|  | 512 | { | 
|  | 513 | err.SetErrorToGenericError(); | 
|  | 514 | err.SetErrorString("Couldn't JIT the function"); | 
|  | 515 | return err; | 
|  | 516 | } | 
|  | 517 |  | 
| Sean Callanan | 3c9c5eb | 2010-09-21 00:44:12 +0000 | [diff] [blame] | 518 | m_jitted_functions.push_back (ClangExpressionParser::JittedFunction(function_name.c_str(), (lldb::addr_t)fun_ptr)); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 519 |  | 
|  | 520 | ExecutionContext &exc_context(exe_ctx); | 
|  | 521 |  | 
|  | 522 | if (exc_context.process == NULL) | 
|  | 523 | { | 
|  | 524 | err.SetErrorToGenericError(); | 
|  | 525 | err.SetErrorString("Couldn't write the JIT compiled code into the target because there is no target"); | 
|  | 526 | return err; | 
|  | 527 | } | 
|  | 528 |  | 
|  | 529 | // Look over the regions allocated for the function compiled.  The JIT | 
|  | 530 | // tries to allocate the functions & stubs close together, so we should try to | 
|  | 531 | // write them that way too... | 
|  | 532 | // For now I only write functions with no stubs, globals, exception tables, | 
|  | 533 | // etc.  So I only need to write the functions. | 
|  | 534 |  | 
|  | 535 | size_t alloc_size = 0; | 
|  | 536 |  | 
|  | 537 | std::map<uint8_t *, uint8_t *>::iterator fun_pos = m_jit_mm->m_functions.begin(); | 
|  | 538 | std::map<uint8_t *, uint8_t *>::iterator fun_end = m_jit_mm->m_functions.end(); | 
|  | 539 |  | 
|  | 540 | for (; fun_pos != fun_end; ++fun_pos) | 
|  | 541 | alloc_size += (*fun_pos).second - (*fun_pos).first; | 
|  | 542 |  | 
|  | 543 | Error alloc_error; | 
|  | 544 | lldb::addr_t target_addr = exc_context.process->AllocateMemory (alloc_size, lldb::ePermissionsReadable|lldb::ePermissionsExecutable, alloc_error); | 
|  | 545 |  | 
|  | 546 | if (target_addr == LLDB_INVALID_ADDRESS) | 
|  | 547 | { | 
|  | 548 | err.SetErrorToGenericError(); | 
|  | 549 | err.SetErrorStringWithFormat("Couldn't allocate memory for the JITted function: %s", alloc_error.AsCString("unknown error")); | 
|  | 550 | return err; | 
|  | 551 | } | 
|  | 552 |  | 
|  | 553 | lldb::addr_t cursor = target_addr; | 
|  | 554 |  | 
|  | 555 | for (fun_pos = m_jit_mm->m_functions.begin(); fun_pos != fun_end; fun_pos++) | 
|  | 556 | { | 
|  | 557 | lldb::addr_t lstart = (lldb::addr_t) (*fun_pos).first; | 
|  | 558 | lldb::addr_t lend = (lldb::addr_t) (*fun_pos).second; | 
|  | 559 | size_t size = lend - lstart; | 
|  | 560 |  | 
|  | 561 | Error write_error; | 
|  | 562 |  | 
|  | 563 | if (exc_context.process->WriteMemory(cursor, (void *) lstart, size, write_error) != size) | 
|  | 564 | { | 
|  | 565 | err.SetErrorToGenericError(); | 
|  | 566 | err.SetErrorStringWithFormat("Couldn't copy JITted function into the target: %s", write_error.AsCString("unknown error")); | 
|  | 567 | return err; | 
|  | 568 | } | 
|  | 569 |  | 
|  | 570 | m_jit_mm->AddToLocalToRemoteMap (lstart, size, cursor); | 
|  | 571 | cursor += size; | 
|  | 572 | } | 
|  | 573 |  | 
|  | 574 | std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); | 
|  | 575 |  | 
|  | 576 | for (pos = m_jitted_functions.begin(); pos != end; pos++) | 
|  | 577 | { | 
|  | 578 | (*pos).m_remote_addr = m_jit_mm->GetRemoteAddressForLocal ((*pos).m_local_addr); | 
|  | 579 |  | 
| Sean Callanan | 3c9c5eb | 2010-09-21 00:44:12 +0000 | [diff] [blame] | 580 | if (!(*pos).m_name.compare(function_name.c_str())) | 
| Sean Callanan | 830a903 | 2010-08-27 23:31:21 +0000 | [diff] [blame] | 581 | { | 
|  | 582 | func_end = m_jit_mm->GetRemoteRangeForLocal ((*pos).m_local_addr).second; | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 583 | func_addr = (*pos).m_remote_addr; | 
| Sean Callanan | 830a903 | 2010-08-27 23:31:21 +0000 | [diff] [blame] | 584 | } | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 585 | } | 
|  | 586 |  | 
| Sean Callanan | 6dff827 | 2010-11-08 03:49:50 +0000 | [diff] [blame] | 587 | if (log) | 
|  | 588 | { | 
|  | 589 | log->Printf("Code can be run in the target."); | 
|  | 590 |  | 
|  | 591 | StreamString disassembly_stream; | 
|  | 592 |  | 
|  | 593 | Error err = DisassembleFunction(disassembly_stream, exe_ctx); | 
|  | 594 |  | 
|  | 595 | if (!err.Success()) | 
|  | 596 | { | 
|  | 597 | log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error")); | 
|  | 598 | } | 
|  | 599 | else | 
|  | 600 | { | 
|  | 601 | log->Printf("Function disassembly:\n%s", disassembly_stream.GetData()); | 
|  | 602 | } | 
|  | 603 | } | 
|  | 604 |  | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 605 | err.Clear(); | 
|  | 606 | return err; | 
|  | 607 | } | 
|  | 608 |  | 
|  | 609 | Error | 
|  | 610 | ClangExpressionParser::DisassembleFunction (Stream &stream, ExecutionContext &exe_ctx) | 
|  | 611 | { | 
| Greg Clayton | e005f2c | 2010-11-06 01:53:30 +0000 | [diff] [blame] | 612 | lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 613 |  | 
|  | 614 | const char *name = m_expr.FunctionName(); | 
|  | 615 |  | 
|  | 616 | Error ret; | 
|  | 617 |  | 
|  | 618 | ret.Clear(); | 
|  | 619 |  | 
|  | 620 | lldb::addr_t func_local_addr = LLDB_INVALID_ADDRESS; | 
|  | 621 | lldb::addr_t func_remote_addr = LLDB_INVALID_ADDRESS; | 
|  | 622 |  | 
|  | 623 | std::vector<JittedFunction>::iterator pos, end = m_jitted_functions.end(); | 
|  | 624 |  | 
|  | 625 | for (pos = m_jitted_functions.begin(); pos < end; pos++) | 
|  | 626 | { | 
| Sean Callanan | 3c9c5eb | 2010-09-21 00:44:12 +0000 | [diff] [blame] | 627 | if (strstr(pos->m_name.c_str(), name)) | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 628 | { | 
|  | 629 | func_local_addr = pos->m_local_addr; | 
|  | 630 | func_remote_addr = pos->m_remote_addr; | 
|  | 631 | } | 
|  | 632 | } | 
|  | 633 |  | 
|  | 634 | if (func_local_addr == LLDB_INVALID_ADDRESS) | 
|  | 635 | { | 
|  | 636 | ret.SetErrorToGenericError(); | 
|  | 637 | ret.SetErrorStringWithFormat("Couldn't find function %s for disassembly", name); | 
|  | 638 | return ret; | 
|  | 639 | } | 
|  | 640 |  | 
|  | 641 | if(log) | 
|  | 642 | log->Printf("Found function, has local address 0x%llx and remote address 0x%llx", (uint64_t)func_local_addr, (uint64_t)func_remote_addr); | 
|  | 643 |  | 
|  | 644 | std::pair <lldb::addr_t, lldb::addr_t> func_range; | 
|  | 645 |  | 
|  | 646 | func_range = m_jit_mm->GetRemoteRangeForLocal(func_local_addr); | 
|  | 647 |  | 
|  | 648 | if (func_range.first == 0 && func_range.second == 0) | 
|  | 649 | { | 
|  | 650 | ret.SetErrorToGenericError(); | 
|  | 651 | ret.SetErrorStringWithFormat("Couldn't find code range for function %s", name); | 
|  | 652 | return ret; | 
|  | 653 | } | 
|  | 654 |  | 
|  | 655 | if(log) | 
|  | 656 | log->Printf("Function's code range is [0x%llx-0x%llx]", func_range.first, func_range.second); | 
|  | 657 |  | 
|  | 658 | if (!exe_ctx.target) | 
|  | 659 | { | 
|  | 660 | ret.SetErrorToGenericError(); | 
|  | 661 | ret.SetErrorString("Couldn't find the target"); | 
|  | 662 | } | 
|  | 663 |  | 
|  | 664 | lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second - func_remote_addr, 0)); | 
|  | 665 |  | 
|  | 666 | Error err; | 
|  | 667 | exe_ctx.process->ReadMemory(func_remote_addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), err); | 
|  | 668 |  | 
|  | 669 | if (!err.Success()) | 
|  | 670 | { | 
|  | 671 | ret.SetErrorToGenericError(); | 
|  | 672 | ret.SetErrorStringWithFormat("Couldn't read from process: %s", err.AsCString("unknown error")); | 
|  | 673 | return ret; | 
|  | 674 | } | 
|  | 675 |  | 
|  | 676 | ArchSpec arch(exe_ctx.target->GetArchitecture()); | 
|  | 677 |  | 
|  | 678 | Disassembler *disassembler = Disassembler::FindPlugin(arch); | 
|  | 679 |  | 
|  | 680 | if (disassembler == NULL) | 
|  | 681 | { | 
|  | 682 | ret.SetErrorToGenericError(); | 
|  | 683 | ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.AsCString()); | 
|  | 684 | return ret; | 
|  | 685 | } | 
|  | 686 |  | 
|  | 687 | if (!exe_ctx.process) | 
|  | 688 | { | 
|  | 689 | ret.SetErrorToGenericError(); | 
|  | 690 | ret.SetErrorString("Couldn't find the process"); | 
|  | 691 | return ret; | 
|  | 692 | } | 
|  | 693 |  | 
|  | 694 | DataExtractor extractor(buffer_sp, | 
|  | 695 | exe_ctx.process->GetByteOrder(), | 
|  | 696 | exe_ctx.target->GetArchitecture().GetAddressByteSize()); | 
|  | 697 |  | 
| Greg Clayton | e005f2c | 2010-11-06 01:53:30 +0000 | [diff] [blame] | 698 | if (log) | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 699 | { | 
|  | 700 | log->Printf("Function data has contents:"); | 
| Greg Clayton | e005f2c | 2010-11-06 01:53:30 +0000 | [diff] [blame] | 701 | extractor.PutToLog (log.get(), | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 702 | 0, | 
|  | 703 | extractor.GetByteSize(), | 
|  | 704 | func_remote_addr, | 
|  | 705 | 16, | 
|  | 706 | DataExtractor::TypeUInt8); | 
|  | 707 | } | 
|  | 708 |  | 
| Greg Clayton | 5c4c746 | 2010-10-06 03:09:58 +0000 | [diff] [blame] | 709 | disassembler->DecodeInstructions (Address (NULL, func_remote_addr), extractor, 0, UINT32_MAX); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 710 |  | 
| Greg Clayton | 5c4c746 | 2010-10-06 03:09:58 +0000 | [diff] [blame] | 711 | InstructionList &instruction_list = disassembler->GetInstructionList(); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 712 |  | 
|  | 713 | uint32_t bytes_offset = 0; | 
|  | 714 |  | 
|  | 715 | for (uint32_t instruction_index = 0, num_instructions = instruction_list.GetSize(); | 
|  | 716 | instruction_index < num_instructions; | 
|  | 717 | ++instruction_index) | 
|  | 718 | { | 
| Greg Clayton | 5c4c746 | 2010-10-06 03:09:58 +0000 | [diff] [blame] | 719 | Instruction *instruction = instruction_list.GetInstructionAtIndex(instruction_index).get(); | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 720 | instruction->Dump (&stream, | 
| Greg Clayton | 5c4c746 | 2010-10-06 03:09:58 +0000 | [diff] [blame] | 721 | true, | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 722 | &extractor, | 
|  | 723 | bytes_offset, | 
| Greg Clayton | 5c4c746 | 2010-10-06 03:09:58 +0000 | [diff] [blame] | 724 | &exe_ctx, | 
| Sean Callanan | 65dafa8 | 2010-08-27 01:01:44 +0000 | [diff] [blame] | 725 | true); | 
|  | 726 | stream.PutChar('\n'); | 
|  | 727 | bytes_offset += instruction->GetByteSize(); | 
|  | 728 | } | 
|  | 729 |  | 
|  | 730 | return ret; | 
|  | 731 | } |