1*30fdc8d8SChris Lattner //===-- ThreadPlanStepUntil.cpp ---------------------------------*- C++ -*-===//
2*30fdc8d8SChris Lattner //
3*30fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
4*30fdc8d8SChris Lattner //
5*30fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
6*30fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
7*30fdc8d8SChris Lattner //
8*30fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
9*30fdc8d8SChris Lattner //m_should_stop
10*30fdc8d8SChris Lattner 
11*30fdc8d8SChris Lattner //
12*30fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
13*30fdc8d8SChris Lattner 
14*30fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanStepUntil.h"
15*30fdc8d8SChris Lattner 
16*30fdc8d8SChris Lattner // C Includes
17*30fdc8d8SChris Lattner // C++ Includes
18*30fdc8d8SChris Lattner // Other libraries and framework includes
19*30fdc8d8SChris Lattner // Project includes
20*30fdc8d8SChris Lattner #include "lldb/Breakpoint/Breakpoint.h"
21*30fdc8d8SChris Lattner #include "lldb/lldb-private-log.h"
22*30fdc8d8SChris Lattner #include "lldb/Core/Log.h"
23*30fdc8d8SChris Lattner #include "lldb/Target/Process.h"
24*30fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
25*30fdc8d8SChris Lattner #include "lldb/Target/Target.h"
26*30fdc8d8SChris Lattner 
27*30fdc8d8SChris Lattner using namespace lldb;
28*30fdc8d8SChris Lattner using namespace lldb_private;
29*30fdc8d8SChris Lattner 
30*30fdc8d8SChris Lattner //----------------------------------------------------------------------
31*30fdc8d8SChris Lattner // ThreadPlanStepUntil: Run until we reach a given line number or step out of the current frame
32*30fdc8d8SChris Lattner //----------------------------------------------------------------------
33*30fdc8d8SChris Lattner 
34*30fdc8d8SChris Lattner ThreadPlanStepUntil::ThreadPlanStepUntil
35*30fdc8d8SChris Lattner (
36*30fdc8d8SChris Lattner     Thread &thread,
37*30fdc8d8SChris Lattner     lldb::addr_t *address_list,
38*30fdc8d8SChris Lattner     size_t num_addresses,
39*30fdc8d8SChris Lattner     bool stop_others
40*30fdc8d8SChris Lattner ) :
41*30fdc8d8SChris Lattner     ThreadPlan ("Step out", thread, eVoteNoOpinion, eVoteNoOpinion),
42*30fdc8d8SChris Lattner     m_step_from_insn (LLDB_INVALID_ADDRESS),
43*30fdc8d8SChris Lattner     m_return_addr (LLDB_INVALID_ADDRESS),
44*30fdc8d8SChris Lattner     m_return_bp_id(LLDB_INVALID_BREAK_ID),
45*30fdc8d8SChris Lattner     m_stepped_out(false),
46*30fdc8d8SChris Lattner     m_should_stop(false),
47*30fdc8d8SChris Lattner     m_explains_stop(false),
48*30fdc8d8SChris Lattner     m_ran_analyze (false),
49*30fdc8d8SChris Lattner     m_stop_others (stop_others)
50*30fdc8d8SChris Lattner {
51*30fdc8d8SChris Lattner 
52*30fdc8d8SChris Lattner     SetOkayToDiscard(true);
53*30fdc8d8SChris Lattner     // Stash away our "until" addresses:
54*30fdc8d8SChris Lattner     Target &target = m_thread.GetProcess().GetTarget();
55*30fdc8d8SChris Lattner 
56*30fdc8d8SChris Lattner     m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
57*30fdc8d8SChris Lattner     lldb::user_id_t thread_id = m_thread.GetID();
58*30fdc8d8SChris Lattner 
59*30fdc8d8SChris Lattner     // Find the return address and set a breakpoint there:
60*30fdc8d8SChris Lattner     // FIXME - can we do this more securely if we know first_insn?
61*30fdc8d8SChris Lattner 
62*30fdc8d8SChris Lattner     StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
63*30fdc8d8SChris Lattner     m_return_addr = return_frame->GetPC().GetLoadAddress(&m_thread.GetProcess());
64*30fdc8d8SChris Lattner     Breakpoint *return_bp = target.CreateBreakpoint (m_return_addr, true).get();
65*30fdc8d8SChris Lattner     if (return_bp != NULL)
66*30fdc8d8SChris Lattner     {
67*30fdc8d8SChris Lattner         return_bp->SetThreadID(thread_id);
68*30fdc8d8SChris Lattner         m_return_bp_id = return_bp->GetID();
69*30fdc8d8SChris Lattner     }
70*30fdc8d8SChris Lattner     else
71*30fdc8d8SChris Lattner     {
72*30fdc8d8SChris Lattner         m_return_bp_id = LLDB_INVALID_BREAK_ID;
73*30fdc8d8SChris Lattner     }
74*30fdc8d8SChris Lattner 
75*30fdc8d8SChris Lattner     m_stack_depth = m_thread.GetStackFrameCount();
76*30fdc8d8SChris Lattner 
77*30fdc8d8SChris Lattner     // Now set breakpoints on all our return addresses:
78*30fdc8d8SChris Lattner     for (int i = 0; i < num_addresses; i++)
79*30fdc8d8SChris Lattner     {
80*30fdc8d8SChris Lattner         Breakpoint *until_bp = target.CreateBreakpoint (address_list[i], true).get();
81*30fdc8d8SChris Lattner         if (until_bp != NULL)
82*30fdc8d8SChris Lattner         {
83*30fdc8d8SChris Lattner             until_bp->SetThreadID(thread_id);
84*30fdc8d8SChris Lattner             m_until_points[address_list[i]] = until_bp->GetID();
85*30fdc8d8SChris Lattner         }
86*30fdc8d8SChris Lattner         else
87*30fdc8d8SChris Lattner         {
88*30fdc8d8SChris Lattner             m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
89*30fdc8d8SChris Lattner         }
90*30fdc8d8SChris Lattner     }
91*30fdc8d8SChris Lattner }
92*30fdc8d8SChris Lattner 
93*30fdc8d8SChris Lattner ThreadPlanStepUntil::~ThreadPlanStepUntil ()
94*30fdc8d8SChris Lattner {
95*30fdc8d8SChris Lattner     Clear();
96*30fdc8d8SChris Lattner }
97*30fdc8d8SChris Lattner 
98*30fdc8d8SChris Lattner void
99*30fdc8d8SChris Lattner ThreadPlanStepUntil::Clear()
100*30fdc8d8SChris Lattner {
101*30fdc8d8SChris Lattner     Target &target = m_thread.GetProcess().GetTarget();
102*30fdc8d8SChris Lattner     if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
103*30fdc8d8SChris Lattner     {
104*30fdc8d8SChris Lattner         target.RemoveBreakpointByID(m_return_bp_id);
105*30fdc8d8SChris Lattner         m_return_bp_id = LLDB_INVALID_BREAK_ID;
106*30fdc8d8SChris Lattner     }
107*30fdc8d8SChris Lattner 
108*30fdc8d8SChris Lattner     until_collection::iterator pos, end = m_until_points.end();
109*30fdc8d8SChris Lattner     for (pos = m_until_points.begin(); pos != end; pos++)
110*30fdc8d8SChris Lattner     {
111*30fdc8d8SChris Lattner         target.RemoveBreakpointByID((*pos).second);
112*30fdc8d8SChris Lattner     }
113*30fdc8d8SChris Lattner     m_until_points.clear();
114*30fdc8d8SChris Lattner }
115*30fdc8d8SChris Lattner 
116*30fdc8d8SChris Lattner void
117*30fdc8d8SChris Lattner ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level)
118*30fdc8d8SChris Lattner {
119*30fdc8d8SChris Lattner     if (level == lldb::eDescriptionLevelBrief)
120*30fdc8d8SChris Lattner     {
121*30fdc8d8SChris Lattner         s->Printf ("step until");
122*30fdc8d8SChris Lattner         if (m_stepped_out)
123*30fdc8d8SChris Lattner             s->Printf (" - stepped out");
124*30fdc8d8SChris Lattner     }
125*30fdc8d8SChris Lattner     else
126*30fdc8d8SChris Lattner     {
127*30fdc8d8SChris Lattner         if (m_until_points.size() == 1)
128*30fdc8d8SChris Lattner             s->Printf ("Stepping from address 0x%llx until we reach 0x%llx using breakpoint %d",
129*30fdc8d8SChris Lattner                        (uint64_t)m_step_from_insn,
130*30fdc8d8SChris Lattner                        (uint64_t) (*m_until_points.begin()).first,
131*30fdc8d8SChris Lattner                        (*m_until_points.begin()).second);
132*30fdc8d8SChris Lattner         else
133*30fdc8d8SChris Lattner         {
134*30fdc8d8SChris Lattner             until_collection::iterator pos, end = m_until_points.end();
135*30fdc8d8SChris Lattner             s->Printf ("Stepping from address 0x%llx until we reach one of:",
136*30fdc8d8SChris Lattner                        (uint64_t)m_step_from_insn);
137*30fdc8d8SChris Lattner             for (pos = m_until_points.begin(); pos != end; pos++)
138*30fdc8d8SChris Lattner             {
139*30fdc8d8SChris Lattner                 s->Printf ("\n\t0x%llx (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
140*30fdc8d8SChris Lattner             }
141*30fdc8d8SChris Lattner         }
142*30fdc8d8SChris Lattner         s->Printf(" stepped out address is 0x%lx.", (uint64_t) m_return_addr);
143*30fdc8d8SChris Lattner     }
144*30fdc8d8SChris Lattner }
145*30fdc8d8SChris Lattner 
146*30fdc8d8SChris Lattner bool
147*30fdc8d8SChris Lattner ThreadPlanStepUntil::ValidatePlan (Stream *error)
148*30fdc8d8SChris Lattner {
149*30fdc8d8SChris Lattner     if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
150*30fdc8d8SChris Lattner         return false;
151*30fdc8d8SChris Lattner     else
152*30fdc8d8SChris Lattner     {
153*30fdc8d8SChris Lattner         until_collection::iterator pos, end = m_until_points.end();
154*30fdc8d8SChris Lattner         for (pos = m_until_points.begin(); pos != end; pos++)
155*30fdc8d8SChris Lattner         {
156*30fdc8d8SChris Lattner             if (!LLDB_BREAK_ID_IS_VALID ((*pos).second))
157*30fdc8d8SChris Lattner                 return false;
158*30fdc8d8SChris Lattner         }
159*30fdc8d8SChris Lattner         return true;
160*30fdc8d8SChris Lattner     }
161*30fdc8d8SChris Lattner }
162*30fdc8d8SChris Lattner 
163*30fdc8d8SChris Lattner void
164*30fdc8d8SChris Lattner ThreadPlanStepUntil::AnalyzeStop()
165*30fdc8d8SChris Lattner {
166*30fdc8d8SChris Lattner     if (m_ran_analyze)
167*30fdc8d8SChris Lattner         return;
168*30fdc8d8SChris Lattner 
169*30fdc8d8SChris Lattner     Thread::StopInfo info;
170*30fdc8d8SChris Lattner     m_should_stop = true;
171*30fdc8d8SChris Lattner     m_explains_stop = false;
172*30fdc8d8SChris Lattner 
173*30fdc8d8SChris Lattner     if (m_thread.GetStopInfo (&info))
174*30fdc8d8SChris Lattner     {
175*30fdc8d8SChris Lattner         StopReason reason = info.GetStopReason();
176*30fdc8d8SChris Lattner 
177*30fdc8d8SChris Lattner         switch (reason)
178*30fdc8d8SChris Lattner         {
179*30fdc8d8SChris Lattner             case eStopReasonBreakpoint:
180*30fdc8d8SChris Lattner             {
181*30fdc8d8SChris Lattner                 // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
182*30fdc8d8SChris Lattner                 BreakpointSiteSP this_site = m_thread.GetProcess().GetBreakpointSiteList().FindByID (info.GetBreakpointSiteID());
183*30fdc8d8SChris Lattner                 if (!this_site)
184*30fdc8d8SChris Lattner                 {
185*30fdc8d8SChris Lattner                     m_explains_stop = false;
186*30fdc8d8SChris Lattner                     return;
187*30fdc8d8SChris Lattner                 }
188*30fdc8d8SChris Lattner 
189*30fdc8d8SChris Lattner                 if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
190*30fdc8d8SChris Lattner                 {
191*30fdc8d8SChris Lattner                     // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
192*30fdc8d8SChris Lattner                     // this is indeed our stop.
193*30fdc8d8SChris Lattner                     // If the stack depth has grown, then we've hit our step out breakpoint recursively.
194*30fdc8d8SChris Lattner                     // If we are the only breakpoint at that location, then we do explain the stop, and
195*30fdc8d8SChris Lattner                     // we'll just continue.
196*30fdc8d8SChris Lattner                     // If there was another breakpoint here, then we don't explain the stop, but we won't
197*30fdc8d8SChris Lattner                     // mark ourselves Completed, because maybe that breakpoint will continue, and then
198*30fdc8d8SChris Lattner                     // we'll finish the "until".
199*30fdc8d8SChris Lattner                     if (m_stack_depth > m_thread.GetStackFrameCount())
200*30fdc8d8SChris Lattner                     {
201*30fdc8d8SChris Lattner                         m_stepped_out = true;
202*30fdc8d8SChris Lattner                         SetPlanComplete();
203*30fdc8d8SChris Lattner                     }
204*30fdc8d8SChris Lattner                     else
205*30fdc8d8SChris Lattner                         m_should_stop = false;
206*30fdc8d8SChris Lattner 
207*30fdc8d8SChris Lattner                     if (this_site->GetNumberOfOwners() == 1)
208*30fdc8d8SChris Lattner                         m_explains_stop = true;
209*30fdc8d8SChris Lattner                     else
210*30fdc8d8SChris Lattner                         m_explains_stop = false;
211*30fdc8d8SChris Lattner                     return;
212*30fdc8d8SChris Lattner                 }
213*30fdc8d8SChris Lattner                 else
214*30fdc8d8SChris Lattner                 {
215*30fdc8d8SChris Lattner                     // Check if we've hit one of our "until" breakpoints.
216*30fdc8d8SChris Lattner                     until_collection::iterator pos, end = m_until_points.end();
217*30fdc8d8SChris Lattner                     for (pos = m_until_points.begin(); pos != end; pos++)
218*30fdc8d8SChris Lattner                     {
219*30fdc8d8SChris Lattner                         if (this_site->IsBreakpointAtThisSite ((*pos).second))
220*30fdc8d8SChris Lattner                         {
221*30fdc8d8SChris Lattner                             // If we're at the right stack depth, then we're done.
222*30fdc8d8SChris Lattner                             if (m_stack_depth == m_thread.GetStackFrameCount())
223*30fdc8d8SChris Lattner                                 SetPlanComplete();
224*30fdc8d8SChris Lattner                             else
225*30fdc8d8SChris Lattner                                 m_should_stop = false;
226*30fdc8d8SChris Lattner 
227*30fdc8d8SChris Lattner                             // Otherwise we've hit this breakpoint recursively.  If we're the
228*30fdc8d8SChris Lattner                             // only breakpoint here, then we do explain the stop, and we'll continue.
229*30fdc8d8SChris Lattner                             // If not then we should let higher plans handle this stop.
230*30fdc8d8SChris Lattner                             if (this_site->GetNumberOfOwners() == 1)
231*30fdc8d8SChris Lattner                                 m_explains_stop = true;
232*30fdc8d8SChris Lattner                             else
233*30fdc8d8SChris Lattner                             {
234*30fdc8d8SChris Lattner                                 m_should_stop = true;
235*30fdc8d8SChris Lattner                                 m_explains_stop = false;
236*30fdc8d8SChris Lattner                             }
237*30fdc8d8SChris Lattner                             return;
238*30fdc8d8SChris Lattner                         }
239*30fdc8d8SChris Lattner                     }
240*30fdc8d8SChris Lattner                 }
241*30fdc8d8SChris Lattner                 // If we get here we haven't hit any of our breakpoints, so let the higher
242*30fdc8d8SChris Lattner                 // plans take care of the stop.
243*30fdc8d8SChris Lattner                 m_explains_stop = false;
244*30fdc8d8SChris Lattner                 return;
245*30fdc8d8SChris Lattner             }
246*30fdc8d8SChris Lattner             case eStopReasonWatchpoint:
247*30fdc8d8SChris Lattner             case eStopReasonSignal:
248*30fdc8d8SChris Lattner             case eStopReasonException:
249*30fdc8d8SChris Lattner                 m_explains_stop = false;
250*30fdc8d8SChris Lattner                 break;
251*30fdc8d8SChris Lattner             default:
252*30fdc8d8SChris Lattner                 m_explains_stop = true;
253*30fdc8d8SChris Lattner                 break;
254*30fdc8d8SChris Lattner         }
255*30fdc8d8SChris Lattner     }
256*30fdc8d8SChris Lattner }
257*30fdc8d8SChris Lattner 
258*30fdc8d8SChris Lattner bool
259*30fdc8d8SChris Lattner ThreadPlanStepUntil::PlanExplainsStop ()
260*30fdc8d8SChris Lattner {
261*30fdc8d8SChris Lattner     // We don't explain signals or breakpoints (breakpoints that handle stepping in or
262*30fdc8d8SChris Lattner     // out will be handled by a child plan.
263*30fdc8d8SChris Lattner     AnalyzeStop();
264*30fdc8d8SChris Lattner     return m_explains_stop;
265*30fdc8d8SChris Lattner }
266*30fdc8d8SChris Lattner 
267*30fdc8d8SChris Lattner bool
268*30fdc8d8SChris Lattner ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
269*30fdc8d8SChris Lattner {
270*30fdc8d8SChris Lattner     // If we've told our self in ExplainsStop that we plan to continue, then
271*30fdc8d8SChris Lattner     // do so here.  Otherwise, as long as this thread has stopped for a reason,
272*30fdc8d8SChris Lattner     // we will stop.
273*30fdc8d8SChris Lattner 
274*30fdc8d8SChris Lattner     Thread::StopInfo stop_info (&m_thread);
275*30fdc8d8SChris Lattner     if (!m_thread.GetStopInfo(&stop_info)
276*30fdc8d8SChris Lattner         || stop_info.GetStopReason() == eStopReasonNone)
277*30fdc8d8SChris Lattner         return false;
278*30fdc8d8SChris Lattner 
279*30fdc8d8SChris Lattner     AnalyzeStop();
280*30fdc8d8SChris Lattner     return m_should_stop;
281*30fdc8d8SChris Lattner }
282*30fdc8d8SChris Lattner 
283*30fdc8d8SChris Lattner bool
284*30fdc8d8SChris Lattner ThreadPlanStepUntil::StopOthers ()
285*30fdc8d8SChris Lattner {
286*30fdc8d8SChris Lattner     return m_stop_others;
287*30fdc8d8SChris Lattner }
288*30fdc8d8SChris Lattner 
289*30fdc8d8SChris Lattner StateType
290*30fdc8d8SChris Lattner ThreadPlanStepUntil::RunState ()
291*30fdc8d8SChris Lattner {
292*30fdc8d8SChris Lattner     return eStateRunning;
293*30fdc8d8SChris Lattner }
294*30fdc8d8SChris Lattner 
295*30fdc8d8SChris Lattner bool
296*30fdc8d8SChris Lattner ThreadPlanStepUntil::WillResume (StateType resume_state, bool current_plan)
297*30fdc8d8SChris Lattner {
298*30fdc8d8SChris Lattner     ThreadPlan::WillResume (resume_state, current_plan);
299*30fdc8d8SChris Lattner     if (current_plan)
300*30fdc8d8SChris Lattner     {
301*30fdc8d8SChris Lattner         Target &target = m_thread.GetProcess().GetTarget();
302*30fdc8d8SChris Lattner         Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
303*30fdc8d8SChris Lattner         if (return_bp != NULL)
304*30fdc8d8SChris Lattner             return_bp->SetEnabled (true);
305*30fdc8d8SChris Lattner 
306*30fdc8d8SChris Lattner         until_collection::iterator pos, end = m_until_points.end();
307*30fdc8d8SChris Lattner         for (pos = m_until_points.begin(); pos != end; pos++)
308*30fdc8d8SChris Lattner         {
309*30fdc8d8SChris Lattner             Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
310*30fdc8d8SChris Lattner             if (until_bp != NULL)
311*30fdc8d8SChris Lattner                 until_bp->SetEnabled (true);
312*30fdc8d8SChris Lattner         }
313*30fdc8d8SChris Lattner     }
314*30fdc8d8SChris Lattner 
315*30fdc8d8SChris Lattner     m_should_stop = true;
316*30fdc8d8SChris Lattner     m_ran_analyze = false;
317*30fdc8d8SChris Lattner     m_explains_stop = false;
318*30fdc8d8SChris Lattner     return true;
319*30fdc8d8SChris Lattner }
320*30fdc8d8SChris Lattner 
321*30fdc8d8SChris Lattner bool
322*30fdc8d8SChris Lattner ThreadPlanStepUntil::WillStop ()
323*30fdc8d8SChris Lattner {
324*30fdc8d8SChris Lattner     Target &target = m_thread.GetProcess().GetTarget();
325*30fdc8d8SChris Lattner     Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get();
326*30fdc8d8SChris Lattner     if (return_bp != NULL)
327*30fdc8d8SChris Lattner         return_bp->SetEnabled (false);
328*30fdc8d8SChris Lattner 
329*30fdc8d8SChris Lattner     until_collection::iterator pos, end = m_until_points.end();
330*30fdc8d8SChris Lattner     for (pos = m_until_points.begin(); pos != end; pos++)
331*30fdc8d8SChris Lattner     {
332*30fdc8d8SChris Lattner         Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get();
333*30fdc8d8SChris Lattner         if (until_bp != NULL)
334*30fdc8d8SChris Lattner             until_bp->SetEnabled (false);
335*30fdc8d8SChris Lattner     }
336*30fdc8d8SChris Lattner     return true;
337*30fdc8d8SChris Lattner }
338*30fdc8d8SChris Lattner 
339*30fdc8d8SChris Lattner bool
340*30fdc8d8SChris Lattner ThreadPlanStepUntil::MischiefManaged ()
341*30fdc8d8SChris Lattner {
342*30fdc8d8SChris Lattner 
343*30fdc8d8SChris Lattner     // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
344*30fdc8d8SChris Lattner     bool done = false;
345*30fdc8d8SChris Lattner     if (IsPlanComplete())
346*30fdc8d8SChris Lattner     {
347*30fdc8d8SChris Lattner         Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
348*30fdc8d8SChris Lattner         if (log)
349*30fdc8d8SChris Lattner             log->Printf("Completed step until plan.");
350*30fdc8d8SChris Lattner 
351*30fdc8d8SChris Lattner         Clear();
352*30fdc8d8SChris Lattner         done = true;
353*30fdc8d8SChris Lattner     }
354*30fdc8d8SChris Lattner     if (done)
355*30fdc8d8SChris Lattner         ThreadPlan::MischiefManaged ();
356*30fdc8d8SChris Lattner 
357*30fdc8d8SChris Lattner     return done;
358*30fdc8d8SChris Lattner 
359*30fdc8d8SChris Lattner }
360*30fdc8d8SChris Lattner 
361