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