1 //===-- SBBreakpointLocation.cpp ------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/API/SBBreakpointLocation.h"
10 #include "lldb/API/SBAddress.h"
11 #include "lldb/API/SBDebugger.h"
12 #include "lldb/API/SBDefines.h"
13 #include "lldb/API/SBStream.h"
14 #include "lldb/API/SBStringList.h"
15 #include "lldb/API/SBStructuredData.h"
16 #include "lldb/Utility/Instrumentation.h"
17 
18 #include "lldb/Breakpoint/Breakpoint.h"
19 #include "lldb/Breakpoint/BreakpointLocation.h"
20 #include "lldb/Core/Debugger.h"
21 #include "lldb/Core/StreamFile.h"
22 #include "lldb/Core/StructuredDataImpl.h"
23 #include "lldb/Interpreter/CommandInterpreter.h"
24 #include "lldb/Interpreter/ScriptInterpreter.h"
25 #include "lldb/Target/Target.h"
26 #include "lldb/Target/ThreadSpec.h"
27 #include "lldb/Utility/Stream.h"
28 #include "lldb/lldb-defines.h"
29 #include "lldb/lldb-types.h"
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 SBBreakpointLocation::SBBreakpointLocation() { LLDB_INSTRUMENT_VA(this); }
35 
36 SBBreakpointLocation::SBBreakpointLocation(
37     const lldb::BreakpointLocationSP &break_loc_sp)
38     : m_opaque_wp(break_loc_sp) {
39   LLDB_INSTRUMENT_VA(this, break_loc_sp);
40 }
41 
42 SBBreakpointLocation::SBBreakpointLocation(const SBBreakpointLocation &rhs)
43     : m_opaque_wp(rhs.m_opaque_wp) {
44   LLDB_INSTRUMENT_VA(this, rhs);
45 }
46 
47 const SBBreakpointLocation &SBBreakpointLocation::
48 operator=(const SBBreakpointLocation &rhs) {
49   LLDB_INSTRUMENT_VA(this, rhs);
50 
51   m_opaque_wp = rhs.m_opaque_wp;
52   return *this;
53 }
54 
55 SBBreakpointLocation::~SBBreakpointLocation() = default;
56 
57 BreakpointLocationSP SBBreakpointLocation::GetSP() const {
58   return m_opaque_wp.lock();
59 }
60 
61 bool SBBreakpointLocation::IsValid() const {
62   LLDB_INSTRUMENT_VA(this);
63   return this->operator bool();
64 }
65 SBBreakpointLocation::operator bool() const {
66   LLDB_INSTRUMENT_VA(this);
67 
68   return bool(GetSP());
69 }
70 
71 SBAddress SBBreakpointLocation::GetAddress() {
72   LLDB_INSTRUMENT_VA(this);
73 
74   BreakpointLocationSP loc_sp = GetSP();
75   if (loc_sp) {
76     return SBAddress(loc_sp->GetAddress());
77   }
78 
79   return SBAddress();
80 }
81 
82 addr_t SBBreakpointLocation::GetLoadAddress() {
83   LLDB_INSTRUMENT_VA(this);
84 
85   addr_t ret_addr = LLDB_INVALID_ADDRESS;
86   BreakpointLocationSP loc_sp = GetSP();
87 
88   if (loc_sp) {
89     std::lock_guard<std::recursive_mutex> guard(
90         loc_sp->GetTarget().GetAPIMutex());
91     ret_addr = loc_sp->GetLoadAddress();
92   }
93 
94   return ret_addr;
95 }
96 
97 void SBBreakpointLocation::SetEnabled(bool enabled) {
98   LLDB_INSTRUMENT_VA(this, enabled);
99 
100   BreakpointLocationSP loc_sp = GetSP();
101   if (loc_sp) {
102     std::lock_guard<std::recursive_mutex> guard(
103         loc_sp->GetTarget().GetAPIMutex());
104     loc_sp->SetEnabled(enabled);
105   }
106 }
107 
108 bool SBBreakpointLocation::IsEnabled() {
109   LLDB_INSTRUMENT_VA(this);
110 
111   BreakpointLocationSP loc_sp = GetSP();
112   if (loc_sp) {
113     std::lock_guard<std::recursive_mutex> guard(
114         loc_sp->GetTarget().GetAPIMutex());
115     return loc_sp->IsEnabled();
116   } else
117     return false;
118 }
119 
120 uint32_t SBBreakpointLocation::GetHitCount() {
121   LLDB_INSTRUMENT_VA(this);
122 
123   BreakpointLocationSP loc_sp = GetSP();
124   if (loc_sp) {
125     std::lock_guard<std::recursive_mutex> guard(
126         loc_sp->GetTarget().GetAPIMutex());
127     return loc_sp->GetHitCount();
128   } else
129     return 0;
130 }
131 
132 uint32_t SBBreakpointLocation::GetIgnoreCount() {
133   LLDB_INSTRUMENT_VA(this);
134 
135   BreakpointLocationSP loc_sp = GetSP();
136   if (loc_sp) {
137     std::lock_guard<std::recursive_mutex> guard(
138         loc_sp->GetTarget().GetAPIMutex());
139     return loc_sp->GetIgnoreCount();
140   } else
141     return 0;
142 }
143 
144 void SBBreakpointLocation::SetIgnoreCount(uint32_t n) {
145   LLDB_INSTRUMENT_VA(this, n);
146 
147   BreakpointLocationSP loc_sp = GetSP();
148   if (loc_sp) {
149     std::lock_guard<std::recursive_mutex> guard(
150         loc_sp->GetTarget().GetAPIMutex());
151     loc_sp->SetIgnoreCount(n);
152   }
153 }
154 
155 void SBBreakpointLocation::SetCondition(const char *condition) {
156   LLDB_INSTRUMENT_VA(this, condition);
157 
158   BreakpointLocationSP loc_sp = GetSP();
159   if (loc_sp) {
160     std::lock_guard<std::recursive_mutex> guard(
161         loc_sp->GetTarget().GetAPIMutex());
162     loc_sp->SetCondition(condition);
163   }
164 }
165 
166 const char *SBBreakpointLocation::GetCondition() {
167   LLDB_INSTRUMENT_VA(this);
168 
169   BreakpointLocationSP loc_sp = GetSP();
170   if (loc_sp) {
171     std::lock_guard<std::recursive_mutex> guard(
172         loc_sp->GetTarget().GetAPIMutex());
173     return loc_sp->GetConditionText();
174   }
175   return nullptr;
176 }
177 
178 void SBBreakpointLocation::SetAutoContinue(bool auto_continue) {
179   LLDB_INSTRUMENT_VA(this, auto_continue);
180 
181   BreakpointLocationSP loc_sp = GetSP();
182   if (loc_sp) {
183     std::lock_guard<std::recursive_mutex> guard(
184         loc_sp->GetTarget().GetAPIMutex());
185     loc_sp->SetAutoContinue(auto_continue);
186   }
187 }
188 
189 bool SBBreakpointLocation::GetAutoContinue() {
190   LLDB_INSTRUMENT_VA(this);
191 
192   BreakpointLocationSP loc_sp = GetSP();
193   if (loc_sp) {
194     std::lock_guard<std::recursive_mutex> guard(
195         loc_sp->GetTarget().GetAPIMutex());
196     return loc_sp->IsAutoContinue();
197   }
198   return false;
199 }
200 
201 void SBBreakpointLocation::SetScriptCallbackFunction(
202   const char *callback_function_name) {
203   LLDB_INSTRUMENT_VA(this, callback_function_name);
204 }
205 
206 SBError SBBreakpointLocation::SetScriptCallbackFunction(
207     const char *callback_function_name,
208     SBStructuredData &extra_args) {
209   LLDB_INSTRUMENT_VA(this, callback_function_name, extra_args);
210   SBError sb_error;
211   BreakpointLocationSP loc_sp = GetSP();
212 
213   if (loc_sp) {
214     Status error;
215     std::lock_guard<std::recursive_mutex> guard(
216         loc_sp->GetTarget().GetAPIMutex());
217     BreakpointOptions &bp_options = loc_sp->GetLocationOptions();
218     error = loc_sp->GetBreakpoint()
219         .GetTarget()
220         .GetDebugger()
221         .GetScriptInterpreter()
222         ->SetBreakpointCommandCallbackFunction(bp_options,
223                                                callback_function_name,
224                                                extra_args.m_impl_up
225                                                    ->GetObjectSP());
226       sb_error.SetError(error);
227     } else
228       sb_error.SetErrorString("invalid breakpoint");
229 
230     return sb_error;
231 }
232 
233 SBError
234 SBBreakpointLocation::SetScriptCallbackBody(const char *callback_body_text) {
235   LLDB_INSTRUMENT_VA(this, callback_body_text);
236 
237   BreakpointLocationSP loc_sp = GetSP();
238 
239   SBError sb_error;
240   if (loc_sp) {
241     std::lock_guard<std::recursive_mutex> guard(
242         loc_sp->GetTarget().GetAPIMutex());
243     BreakpointOptions &bp_options = loc_sp->GetLocationOptions();
244     Status error =
245         loc_sp->GetBreakpoint()
246             .GetTarget()
247             .GetDebugger()
248             .GetScriptInterpreter()
249             ->SetBreakpointCommandCallback(bp_options, callback_body_text);
250     sb_error.SetError(error);
251   } else
252     sb_error.SetErrorString("invalid breakpoint");
253 
254   return sb_error;
255 }
256 
257 void SBBreakpointLocation::SetCommandLineCommands(SBStringList &commands) {
258   LLDB_INSTRUMENT_VA(this, commands);
259 
260   BreakpointLocationSP loc_sp = GetSP();
261   if (!loc_sp)
262     return;
263   if (commands.GetSize() == 0)
264     return;
265 
266   std::lock_guard<std::recursive_mutex> guard(
267       loc_sp->GetTarget().GetAPIMutex());
268   std::unique_ptr<BreakpointOptions::CommandData> cmd_data_up(
269       new BreakpointOptions::CommandData(*commands, eScriptLanguageNone));
270 
271   loc_sp->GetLocationOptions().SetCommandDataCallback(cmd_data_up);
272 }
273 
274 bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) {
275   LLDB_INSTRUMENT_VA(this, commands);
276 
277   BreakpointLocationSP loc_sp = GetSP();
278   if (!loc_sp)
279     return false;
280   StringList command_list;
281   bool has_commands =
282       loc_sp->GetLocationOptions().GetCommandLineCallbacks(command_list);
283   if (has_commands)
284     commands.AppendList(command_list);
285   return has_commands;
286 }
287 
288 void SBBreakpointLocation::SetThreadID(tid_t thread_id) {
289   LLDB_INSTRUMENT_VA(this, thread_id);
290 
291   BreakpointLocationSP loc_sp = GetSP();
292   if (loc_sp) {
293     std::lock_guard<std::recursive_mutex> guard(
294         loc_sp->GetTarget().GetAPIMutex());
295     loc_sp->SetThreadID(thread_id);
296   }
297 }
298 
299 tid_t SBBreakpointLocation::GetThreadID() {
300   LLDB_INSTRUMENT_VA(this);
301 
302   tid_t tid = LLDB_INVALID_THREAD_ID;
303   BreakpointLocationSP loc_sp = GetSP();
304   if (loc_sp) {
305     std::lock_guard<std::recursive_mutex> guard(
306         loc_sp->GetTarget().GetAPIMutex());
307     return loc_sp->GetThreadID();
308   }
309   return tid;
310 }
311 
312 void SBBreakpointLocation::SetThreadIndex(uint32_t index) {
313   LLDB_INSTRUMENT_VA(this, index);
314 
315   BreakpointLocationSP loc_sp = GetSP();
316   if (loc_sp) {
317     std::lock_guard<std::recursive_mutex> guard(
318         loc_sp->GetTarget().GetAPIMutex());
319     loc_sp->SetThreadIndex(index);
320   }
321 }
322 
323 uint32_t SBBreakpointLocation::GetThreadIndex() const {
324   LLDB_INSTRUMENT_VA(this);
325 
326   uint32_t thread_idx = UINT32_MAX;
327   BreakpointLocationSP loc_sp = GetSP();
328   if (loc_sp) {
329     std::lock_guard<std::recursive_mutex> guard(
330         loc_sp->GetTarget().GetAPIMutex());
331     return loc_sp->GetThreadIndex();
332   }
333   return thread_idx;
334 }
335 
336 void SBBreakpointLocation::SetThreadName(const char *thread_name) {
337   LLDB_INSTRUMENT_VA(this, thread_name);
338 
339   BreakpointLocationSP loc_sp = GetSP();
340   if (loc_sp) {
341     std::lock_guard<std::recursive_mutex> guard(
342         loc_sp->GetTarget().GetAPIMutex());
343     loc_sp->SetThreadName(thread_name);
344   }
345 }
346 
347 const char *SBBreakpointLocation::GetThreadName() const {
348   LLDB_INSTRUMENT_VA(this);
349 
350   BreakpointLocationSP loc_sp = GetSP();
351   if (loc_sp) {
352     std::lock_guard<std::recursive_mutex> guard(
353         loc_sp->GetTarget().GetAPIMutex());
354     return loc_sp->GetThreadName();
355   }
356   return nullptr;
357 }
358 
359 void SBBreakpointLocation::SetQueueName(const char *queue_name) {
360   LLDB_INSTRUMENT_VA(this, queue_name);
361 
362   BreakpointLocationSP loc_sp = GetSP();
363   if (loc_sp) {
364     std::lock_guard<std::recursive_mutex> guard(
365         loc_sp->GetTarget().GetAPIMutex());
366     loc_sp->SetQueueName(queue_name);
367   }
368 }
369 
370 const char *SBBreakpointLocation::GetQueueName() const {
371   LLDB_INSTRUMENT_VA(this);
372 
373   BreakpointLocationSP loc_sp = GetSP();
374   if (loc_sp) {
375     std::lock_guard<std::recursive_mutex> guard(
376         loc_sp->GetTarget().GetAPIMutex());
377     loc_sp->GetQueueName();
378   }
379   return nullptr;
380 }
381 
382 bool SBBreakpointLocation::IsResolved() {
383   LLDB_INSTRUMENT_VA(this);
384 
385   BreakpointLocationSP loc_sp = GetSP();
386   if (loc_sp) {
387     std::lock_guard<std::recursive_mutex> guard(
388         loc_sp->GetTarget().GetAPIMutex());
389     return loc_sp->IsResolved();
390   }
391   return false;
392 }
393 
394 void SBBreakpointLocation::SetLocation(
395     const lldb::BreakpointLocationSP &break_loc_sp) {
396   // Uninstall the callbacks?
397   m_opaque_wp = break_loc_sp;
398 }
399 
400 bool SBBreakpointLocation::GetDescription(SBStream &description,
401                                           DescriptionLevel level) {
402   LLDB_INSTRUMENT_VA(this, description, level);
403 
404   Stream &strm = description.ref();
405   BreakpointLocationSP loc_sp = GetSP();
406 
407   if (loc_sp) {
408     std::lock_guard<std::recursive_mutex> guard(
409         loc_sp->GetTarget().GetAPIMutex());
410     loc_sp->GetDescription(&strm, level);
411     strm.EOL();
412   } else
413     strm.PutCString("No value");
414 
415   return true;
416 }
417 
418 break_id_t SBBreakpointLocation::GetID() {
419   LLDB_INSTRUMENT_VA(this);
420 
421   BreakpointLocationSP loc_sp = GetSP();
422   if (loc_sp) {
423     std::lock_guard<std::recursive_mutex> guard(
424         loc_sp->GetTarget().GetAPIMutex());
425     return loc_sp->GetID();
426   } else
427     return LLDB_INVALID_BREAK_ID;
428 }
429 
430 SBBreakpoint SBBreakpointLocation::GetBreakpoint() {
431   LLDB_INSTRUMENT_VA(this);
432 
433   BreakpointLocationSP loc_sp = GetSP();
434 
435   SBBreakpoint sb_bp;
436   if (loc_sp) {
437     std::lock_guard<std::recursive_mutex> guard(
438         loc_sp->GetTarget().GetAPIMutex());
439     sb_bp = loc_sp->GetBreakpoint().shared_from_this();
440   }
441 
442   return sb_bp;
443 }
444