1 //===-- StopInfo.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/Target/StopInfo.h"
11 
12 // C Includes
13 // C++ Includes
14 #include <string>
15 
16 // Other libraries and framework includes
17 // Project includes
18 #include "lldb/Core/Log.h"
19 #include "lldb/Breakpoint/Breakpoint.h"
20 #include "lldb/Breakpoint/BreakpointLocation.h"
21 #include "lldb/Breakpoint/StoppointCallbackContext.h"
22 #include "lldb/Core/StreamString.h"
23 #include "lldb/Target/Thread.h"
24 #include "lldb/Target/ThreadPlan.h"
25 #include "lldb/Target/Process.h"
26 #include "lldb/Target/UnixSignals.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 StopInfo::StopInfo (Thread &thread, uint64_t value) :
32     m_thread (thread),
33     m_stop_id (thread.GetProcess().GetStopID()),
34     m_value (value)
35 {
36 }
37 
38 bool
39 StopInfo::IsValid () const
40 {
41     return m_thread.GetProcess().GetStopID() == m_stop_id;
42 }
43 
44 void
45 StopInfo::MakeStopInfoValid ()
46 {
47     m_stop_id = m_thread.GetProcess().GetStopID();
48 }
49 
50 //----------------------------------------------------------------------
51 // StopInfoBreakpoint
52 //----------------------------------------------------------------------
53 
54 class StopInfoBreakpoint : public StopInfo
55 {
56 public:
57 
58     StopInfoBreakpoint (Thread &thread, break_id_t break_id) :
59         StopInfo (thread, break_id),
60         m_description(),
61         m_should_stop (false),
62         m_should_stop_is_valid (false)
63     {
64     }
65 
66     StopInfoBreakpoint (Thread &thread, break_id_t break_id, bool should_stop) :
67         StopInfo (thread, break_id),
68         m_description(),
69         m_should_stop (should_stop),
70         m_should_stop_is_valid (true)
71     {
72     }
73 
74     virtual ~StopInfoBreakpoint ()
75     {
76     }
77 
78     virtual StopReason
79     GetStopReason () const
80     {
81         return eStopReasonBreakpoint;
82     }
83 
84     virtual bool
85     ShouldStop (Event *event_ptr)
86     {
87         if (!m_should_stop_is_valid)
88         {
89             // Only check once if we should stop at a breakpoint
90             BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (m_value));
91             if (bp_site_sp)
92             {
93                 StoppointCallbackContext context (event_ptr,
94                                                   &m_thread.GetProcess(),
95                                                   &m_thread,
96                                                   m_thread.GetStackFrameAtIndex(0).get(),
97                                                   true);
98 
99                 m_should_stop = bp_site_sp->ShouldStop (&context);
100             }
101             else
102             {
103                 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
104 
105                 if (log)
106                     log->Printf ("Process::%s could not find breakpoint site id: %lld...", __FUNCTION__, m_value);
107 
108                 m_should_stop = true;
109             }
110             m_should_stop_is_valid = true;
111         }
112         return m_should_stop;
113     }
114 
115     virtual void
116     PerformAction (Event *event_ptr)
117     {
118         BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (m_value));
119         if (bp_site_sp)
120         {
121             size_t num_owners = bp_site_sp->GetNumberOfOwners();
122             for (size_t j = 0; j < num_owners; j++)
123             {
124                 // The breakpoint action is an asynchronous breakpoint callback.  If we ever need to have both
125                 // callbacks and actions on the same breakpoint, we'll have to split this into two.
126                 lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
127                 StoppointCallbackContext context (event_ptr,
128                                                   &m_thread.GetProcess(),
129                                                   &m_thread,
130                                                   m_thread.GetStackFrameAtIndex(0).get(),
131                                                   false);
132                 bp_loc_sp->InvokeCallback (&context);
133             }
134         }
135         else
136         {
137             LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
138 
139             if (log)
140                 log->Printf ("Process::%s could not find breakpoint site id: %lld...", __FUNCTION__, m_value);
141         }
142     }
143 
144     virtual bool
145     ShouldNotify (Event *event_ptr)
146     {
147         BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (m_value));
148         if (bp_site_sp)
149         {
150             bool all_internal = true;
151 
152             for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++)
153             {
154                 if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal())
155                 {
156                     all_internal = false;
157                     break;
158                 }
159             }
160             return all_internal == false;
161         }
162         return true;
163     }
164 
165     virtual const char *
166     GetDescription ()
167     {
168         if (m_description.empty())
169         {
170             BreakpointSiteSP bp_site_sp (m_thread.GetProcess().GetBreakpointSiteList().FindByID (m_value));
171             if (bp_site_sp)
172             {
173                 StreamString strm;
174                 strm.Printf("breakpoint ");
175                 bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
176                 m_description.swap (strm.GetString());
177             }
178             else
179             {
180                 StreamString strm;
181                 strm.Printf("breakpoint site %lli", m_value);
182                 m_description.swap (strm.GetString());
183             }
184         }
185         return m_description.c_str();
186     }
187 
188 private:
189     std::string m_description;
190     bool m_should_stop;
191     bool m_should_stop_is_valid;
192 };
193 
194 
195 //----------------------------------------------------------------------
196 // StopInfoWatchpoint
197 //----------------------------------------------------------------------
198 
199 class StopInfoWatchpoint : public StopInfo
200 {
201 public:
202 
203     StopInfoWatchpoint (Thread &thread, break_id_t watch_id) :
204         StopInfo (thread, watch_id),
205         m_description()
206     {
207     }
208 
209     virtual ~StopInfoWatchpoint ()
210     {
211     }
212 
213     virtual StopReason
214     GetStopReason () const
215     {
216         return eStopReasonWatchpoint;
217     }
218 
219     virtual const char *
220     GetDescription ()
221     {
222         if (m_description.empty())
223         {
224             StreamString strm;
225             strm.Printf("watchpoint %lli", m_value);
226             m_description.swap (strm.GetString());
227         }
228         return m_description.c_str();
229     }
230 
231 
232 
233 private:
234     std::string m_description;
235 };
236 
237 
238 
239 //----------------------------------------------------------------------
240 // StopInfoUnixSignal
241 //----------------------------------------------------------------------
242 
243 class StopInfoUnixSignal : public StopInfo
244 {
245 public:
246 
247     StopInfoUnixSignal (Thread &thread, int signo) :
248         StopInfo (thread, signo),
249         m_description()
250     {
251     }
252 
253     virtual ~StopInfoUnixSignal ()
254     {
255     }
256 
257 
258     virtual StopReason
259     GetStopReason () const
260     {
261         return eStopReasonSignal;
262     }
263 
264     virtual bool
265     ShouldStop (Event *event_ptr)
266     {
267         return m_thread.GetProcess().GetUnixSignals().GetShouldStop (m_value);
268     }
269 
270 
271     // If should stop returns false, check if we should notify of this event
272     virtual bool
273     ShouldNotify (Event *event_ptr)
274     {
275         return m_thread.GetProcess().GetUnixSignals().GetShouldNotify (m_value);
276     }
277 
278 
279     virtual void
280     WillResume (lldb::StateType resume_state)
281     {
282         if (m_thread.GetProcess().GetUnixSignals().GetShouldSuppress(m_value) == false)
283             m_thread.SetResumeSignal(m_value);
284     }
285 
286     virtual const char *
287     GetDescription ()
288     {
289         if (m_description.empty())
290         {
291             StreamString strm;
292             const char *signal_name = m_thread.GetProcess().GetUnixSignals().GetSignalAsCString (m_value);
293             if (signal_name)
294                 strm.Printf("signal %s", signal_name);
295             else
296                 strm.Printf("signal %lli", m_value);
297             m_description.swap (strm.GetString());
298         }
299         return m_description.c_str();
300     }
301 
302 private:
303     std::string m_description;
304 };
305 
306 //----------------------------------------------------------------------
307 // StopInfoTrace
308 //----------------------------------------------------------------------
309 
310 class StopInfoTrace : public StopInfo
311 {
312 public:
313 
314     StopInfoTrace (Thread &thread) :
315         StopInfo (thread, LLDB_INVALID_UID)
316     {
317     }
318 
319     virtual ~StopInfoTrace ()
320     {
321     }
322 
323     virtual StopReason
324     GetStopReason () const
325     {
326         return eStopReasonTrace;
327     }
328 
329     virtual const char *
330     GetDescription ()
331     {
332         return "trace";
333     }
334 };
335 
336 
337 //----------------------------------------------------------------------
338 // StopInfoThreadPlan
339 //----------------------------------------------------------------------
340 
341 class StopInfoThreadPlan : public StopInfo
342 {
343 public:
344 
345     StopInfoThreadPlan (ThreadPlanSP &plan_sp) :
346         StopInfo (plan_sp->GetThread(), LLDB_INVALID_UID),
347         m_plan_sp (plan_sp)
348     {
349     }
350 
351     virtual ~StopInfoThreadPlan ()
352     {
353     }
354 
355     virtual StopReason
356     GetStopReason () const
357     {
358         return eStopReasonPlanComplete;
359     }
360 
361     virtual const char *
362     GetDescription ()
363     {
364         if (m_description.empty())
365         {
366             StreamString strm;
367             m_plan_sp->GetDescription (&strm, eDescriptionLevelBrief);
368             m_description.swap (strm.GetString());
369         }
370         return m_description.c_str();
371     }
372 
373 private:
374     ThreadPlanSP m_plan_sp;
375     std::string m_description;
376 };
377 
378 StopInfoSP
379 StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id)
380 {
381     return StopInfoSP (new StopInfoBreakpoint (thread, break_id));
382 }
383 
384 StopInfoSP
385 StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id, bool should_stop)
386 {
387     return StopInfoSP (new StopInfoBreakpoint (thread, break_id, should_stop));
388 }
389 
390 StopInfoSP
391 StopInfo::CreateStopReasonWithWatchpointID (Thread &thread, break_id_t watch_id)
392 {
393     return StopInfoSP (new StopInfoWatchpoint (thread, watch_id));
394 }
395 
396 StopInfoSP
397 StopInfo::CreateStopReasonWithSignal (Thread &thread, int signo)
398 {
399     return StopInfoSP (new StopInfoUnixSignal (thread, signo));
400 }
401 
402 StopInfoSP
403 StopInfo::CreateStopReasonToTrace (Thread &thread)
404 {
405     return StopInfoSP (new StopInfoTrace (thread));
406 }
407 
408 StopInfoSP
409 StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp)
410 {
411     return StopInfoSP (new StopInfoThreadPlan (plan_sp));
412 }
413