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