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