blob: afd94bbd6a89fc1984d2a7294cfff6af1dce27ff [file] [log] [blame]
Sean Callanan65dafa82010-08-27 01:01:44 +00001//===-- ClangUserExpression.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// C Includes
11#include <stdio.h>
12#if HAVE_SYS_TYPES_H
13# include <sys/types.h>
14#endif
15
16// C++ Includes
17#include <cstdlib>
18#include <string>
19#include <map>
20
21#include "lldb/Core/ConstString.h"
22#include "lldb/Core/Log.h"
23#include "lldb/Core/StreamString.h"
24#include "lldb/Expression/ClangExpressionDeclMap.h"
25#include "lldb/Expression/ClangExpressionParser.h"
26#include "lldb/Expression/ClangFunction.h"
27#include "lldb/Expression/ASTResultSynthesizer.h"
28#include "lldb/Expression/ClangUserExpression.h"
29#include "lldb/Host/Host.h"
30#include "lldb/Target/ExecutionContext.h"
31#include "lldb/Target/Target.h"
32
33using namespace lldb_private;
34
35ClangUserExpression::ClangUserExpression (const char *expr) :
36 m_expr_text(expr),
37 m_jit_addr(LLDB_INVALID_ADDRESS)
38{
39 StreamString m_transformed_stream;
40
41 m_transformed_stream.Printf("extern \"C\" void %s(void *___clang_arg) { %s; }\n",
42 FunctionName(),
43 m_expr_text.c_str());
44
45 m_transformed_text = m_transformed_stream.GetData();
46}
47
48clang::ASTConsumer *
49ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough)
50{
51 return new ASTResultSynthesizer(passthrough);
52}
53
54bool
55ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx)
56{
57 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
58
59 ////////////////////////////////////
60 // Set up the target and compiler
61 //
62
63 Target *target = exe_ctx.target;
64
65 if (!target)
66 {
67 error_stream.PutCString ("error: invalid target\n");
68 return false;
69 }
70
71 ConstString target_triple;
72
73 target->GetTargetTriple (target_triple);
74
75 if (!target_triple)
76 target_triple = Host::GetTargetTriple ();
77
78 if (!target_triple)
79 {
80 error_stream.PutCString ("error: invalid target triple\n");
81 return false;
82 }
83
84 //////////////////////////
85 // Parse the expression
86 //
87
88 m_expr_decl_map.reset(new ClangExpressionDeclMap(&exe_ctx));
89
90 ClangExpressionParser parser(target_triple.GetCString(), *this);
91
92 unsigned num_errors = parser.Parse (error_stream);
93
94 if (num_errors)
95 {
96 error_stream.Printf ("error: %d errors parsing expression\n", num_errors);
97 return false;
98 }
99
100 ///////////////////////////////////////////////
101 // Convert the output of the parser to DWARF
102 //
103
104 m_dwarf_opcodes.reset(new StreamString);
105 m_dwarf_opcodes->SetByteOrder (lldb::eByteOrderHost);
106 m_dwarf_opcodes->GetFlags ().Set (Stream::eBinary);
107
108 m_local_variables.reset(new ClangExpressionVariableStore());
109
110 Error dwarf_error = parser.MakeDWARF ();
111
112 if (dwarf_error.Success())
113 {
114 if (log)
115 log->Printf("Code can be interpreted.");
116
117 return true;
118 }
119
120 //////////////////////////////////
121 // JIT the output of the parser
122 //
123
124 m_dwarf_opcodes.reset();
125
126 Error jit_error = parser.MakeJIT (m_jit_addr, exe_ctx);
127
128 if (jit_error.Success())
129 {
130 if (log)
131 {
132 log->Printf("Code can be run in the target.");
133
134 StreamString disassembly_stream;
135
136 Error err = parser.DisassembleFunction(disassembly_stream, exe_ctx);
137
138 if (!err.Success())
139 {
140 log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error"));
141 }
142 else
143 {
144 log->Printf("Function disassembly:\n%s", disassembly_stream.GetData());
145 }
146 }
147
148 return true;
149 }
150 else
151 {
152 error_stream.Printf ("error: expression can't be interpreted or run\n", num_errors);
153 return false;
154 }
155}
156
157bool
158ClangUserExpression::Execute (Stream &error_stream,
159 ExecutionContext &exe_ctx,
160 ClangExpressionVariable *&result)
161{
162 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
163
164 if (m_dwarf_opcodes.get())
165 {
166 // TODO execute the JITted opcodes
167
168 error_stream.Printf("We don't currently support executing DWARF expressions");
169
170 return false;
171 }
172 else if (m_jit_addr != LLDB_INVALID_ADDRESS)
173 {
174 lldb::addr_t struct_address;
175
176 Error materialize_error;
177
178 if (!m_expr_decl_map->Materialize(&exe_ctx, struct_address, materialize_error))
179 {
180 error_stream.Printf("Couldn't materialize struct: %s\n", materialize_error.AsCString("unknown error"));
181 return false;
182 }
183
184 if (log)
185 {
186 log->Printf("Function address : 0x%llx", (uint64_t)m_jit_addr);
187 log->Printf("Structure address : 0x%llx", (uint64_t)struct_address);
188
189 StreamString args;
190
191 Error dump_error;
192
193 if (!m_expr_decl_map->DumpMaterializedStruct(&exe_ctx, args, dump_error))
194 {
195 log->Printf("Couldn't extract variable values : %s", dump_error.AsCString("unknown error"));
196 }
197 else
198 {
199 log->Printf("Structure contents:\n%s", args.GetData());
200 }
201 }
202
203 ClangFunction::ExecutionResults execution_result =
204 ClangFunction::ExecuteFunction (exe_ctx, m_jit_addr, struct_address, true, true, 10000, error_stream);
205
206 if (execution_result != ClangFunction::eExecutionCompleted)
207 {
208 const char *result_name;
209
210 switch (execution_result)
211 {
212 case ClangFunction::eExecutionCompleted:
213 result_name = "eExecutionCompleted";
214 break;
215 case ClangFunction::eExecutionDiscarded:
216 result_name = "eExecutionDiscarded";
217 break;
218 case ClangFunction::eExecutionInterrupted:
219 result_name = "eExecutionInterrupted";
220 break;
221 case ClangFunction::eExecutionSetupError:
222 result_name = "eExecutionSetupError";
223 break;
224 case ClangFunction::eExecutionTimedOut:
225 result_name = "eExecutionTimedOut";
226 break;
227 }
228
229 error_stream.Printf ("Couldn't execute function; result was %s\n", result_name);
230 return false;
231 }
232
233 Error expr_error;
234
235 if (!m_expr_decl_map->Dematerialize(&exe_ctx, result, expr_error))
236 {
237 error_stream.Printf ("Couldn't dematerialize struct : %s\n", expr_error.AsCString("unknown error"));
238 return false;
239 }
240
241 return true;
242 }
243 else
244 {
245 error_stream.Printf("Expression can't be run; neither DWARF nor a JIT compiled function are present");
246 return false;
247 }
248}
249
250StreamString &
251ClangUserExpression::DwarfOpcodeStream ()
252{
253 if (!m_dwarf_opcodes.get())
254 m_dwarf_opcodes.reset(new StreamString());
255
256 return *m_dwarf_opcodes.get();
257}