Bug Summary

File:build/source/lldb/source/Breakpoint/BreakpointOptions.cpp
Warning:line 64, column 8
Value stored to 'success' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name BreakpointOptions.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -isystem /usr/include/libxml2 -D HAVE_ROUND -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/lldb/source/Breakpoint -I /build/source/lldb/source/Breakpoint -I /build/source/lldb/include -I tools/lldb/include -I include -I /build/source/llvm/include -I /usr/include/python3.9 -I /build/source/clang/include -I tools/lldb/../clang/include -I /build/source/lldb/source -I tools/lldb/source -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-stringop-truncation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/lldb/source/Breakpoint/BreakpointOptions.cpp
1//===-- BreakpointOptions.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/Breakpoint/BreakpointOptions.h"
10
11#include "lldb/Breakpoint/StoppointCallbackContext.h"
12#include "lldb/Core/Value.h"
13#include "lldb/Interpreter/CommandInterpreter.h"
14#include "lldb/Interpreter/CommandReturnObject.h"
15#include "lldb/Target/Process.h"
16#include "lldb/Target/Target.h"
17#include "lldb/Target/ThreadSpec.h"
18#include "lldb/Utility/Stream.h"
19#include "lldb/Utility/StringList.h"
20
21#include "llvm/ADT/STLExtras.h"
22
23using namespace lldb;
24using namespace lldb_private;
25
26const char
27 *BreakpointOptions::CommandData::g_option_names[static_cast<uint32_t>(
28 BreakpointOptions::CommandData::OptionNames::LastOptionName)]{
29 "UserSource", "ScriptSource", "StopOnError"};
30
31StructuredData::ObjectSP
32BreakpointOptions::CommandData::SerializeToStructuredData() {
33 size_t num_strings = user_source.GetSize();
34 if (num_strings == 0 && script_source.empty()) {
35 // We shouldn't serialize commands if there aren't any, return an empty sp
36 // to indicate this.
37 return StructuredData::ObjectSP();
38 }
39
40 StructuredData::DictionarySP options_dict_sp(
41 new StructuredData::Dictionary());
42 options_dict_sp->AddBooleanItem(GetKey(OptionNames::StopOnError),
43 stop_on_error);
44
45 StructuredData::ArraySP user_source_sp(new StructuredData::Array());
46 for (size_t i = 0; i < num_strings; i++) {
47 StructuredData::StringSP item_sp(
48 new StructuredData::String(user_source[i]));
49 user_source_sp->AddItem(item_sp);
50 options_dict_sp->AddItem(GetKey(OptionNames::UserSource), user_source_sp);
51 }
52
53 options_dict_sp->AddStringItem(
54 GetKey(OptionNames::Interpreter),
55 ScriptInterpreter::LanguageToString(interpreter));
56 return options_dict_sp;
57}
58
59std::unique_ptr<BreakpointOptions::CommandData>
60BreakpointOptions::CommandData::CreateFromStructuredData(
61 const StructuredData::Dictionary &options_dict, Status &error) {
62 std::unique_ptr<CommandData> data_up(new CommandData());
63
64 bool success = options_dict.GetValueForKeyAsBoolean(
Value stored to 'success' during its initialization is never read
65 GetKey(OptionNames::StopOnError), data_up->stop_on_error);
66
67 llvm::StringRef interpreter_str;
68 ScriptLanguage interp_language;
69 success = options_dict.GetValueForKeyAsString(
70 GetKey(OptionNames::Interpreter), interpreter_str);
71
72 if (!success) {
73 error.SetErrorString("Missing command language value.");
74 return data_up;
75 }
76
77 interp_language = ScriptInterpreter::StringToLanguage(interpreter_str);
78 if (interp_language == eScriptLanguageUnknown) {
79 error.SetErrorStringWithFormatv("Unknown breakpoint command language: {0}.",
80 interpreter_str);
81 return data_up;
82 }
83 data_up->interpreter = interp_language;
84
85 StructuredData::Array *user_source;
86 success = options_dict.GetValueForKeyAsArray(GetKey(OptionNames::UserSource),
87 user_source);
88 if (success) {
89 size_t num_elems = user_source->GetSize();
90 for (size_t i = 0; i < num_elems; i++) {
91 llvm::StringRef elem_string;
92 success = user_source->GetItemAtIndexAsString(i, elem_string);
93 if (success)
94 data_up->user_source.AppendString(elem_string);
95 }
96 }
97
98 return data_up;
99}
100
101const char *BreakpointOptions::g_option_names[(
102 size_t)BreakpointOptions::OptionNames::LastOptionName]{
103 "ConditionText", "IgnoreCount",
104 "EnabledState", "OneShotState", "AutoContinue"};
105
106bool BreakpointOptions::NullCallback(void *baton,
107 StoppointCallbackContext *context,
108 lldb::user_id_t break_id,
109 lldb::user_id_t break_loc_id) {
110 return true;
111}
112
113// BreakpointOptions constructor
114BreakpointOptions::BreakpointOptions(bool all_flags_set)
115 : m_callback(BreakpointOptions::NullCallback),
116 m_baton_is_command_baton(false), m_callback_is_synchronous(false),
117 m_enabled(true), m_one_shot(false), m_ignore_count(0),
118 m_condition_text_hash(0), m_inject_condition(false),
119 m_auto_continue(false), m_set_flags(0) {
120 if (all_flags_set)
121 m_set_flags.Set(~((Flags::ValueType)0));
122}
123
124BreakpointOptions::BreakpointOptions(const char *condition, bool enabled,
125 int32_t ignore, bool one_shot,
126 bool auto_continue)
127 : m_callback(nullptr), m_baton_is_command_baton(false),
128 m_callback_is_synchronous(false), m_enabled(enabled),
129 m_one_shot(one_shot), m_ignore_count(ignore), m_condition_text_hash(0),
130 m_inject_condition(false), m_auto_continue(auto_continue) {
131 m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot | eAutoContinue);
132 if (condition && *condition != '\0') {
133 SetCondition(condition);
134 }
135}
136
137// BreakpointOptions copy constructor
138BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs)
139 : m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp),
140 m_baton_is_command_baton(rhs.m_baton_is_command_baton),
141 m_callback_is_synchronous(rhs.m_callback_is_synchronous),
142 m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot),
143 m_ignore_count(rhs.m_ignore_count), m_inject_condition(false),
144 m_auto_continue(rhs.m_auto_continue), m_set_flags(rhs.m_set_flags) {
145 if (rhs.m_thread_spec_up != nullptr)
146 m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
147 m_condition_text = rhs.m_condition_text;
148 m_condition_text_hash = rhs.m_condition_text_hash;
149}
150
151// BreakpointOptions assignment operator
152const BreakpointOptions &BreakpointOptions::
153operator=(const BreakpointOptions &rhs) {
154 m_callback = rhs.m_callback;
155 m_callback_baton_sp = rhs.m_callback_baton_sp;
156 m_baton_is_command_baton = rhs.m_baton_is_command_baton;
157 m_callback_is_synchronous = rhs.m_callback_is_synchronous;
158 m_enabled = rhs.m_enabled;
159 m_one_shot = rhs.m_one_shot;
160 m_ignore_count = rhs.m_ignore_count;
161 if (rhs.m_thread_spec_up != nullptr)
162 m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
163 m_condition_text = rhs.m_condition_text;
164 m_condition_text_hash = rhs.m_condition_text_hash;
165 m_inject_condition = rhs.m_inject_condition;
166 m_auto_continue = rhs.m_auto_continue;
167 m_set_flags = rhs.m_set_flags;
168 return *this;
169}
170
171void BreakpointOptions::CopyOverSetOptions(const BreakpointOptions &incoming)
172{
173 if (incoming.m_set_flags.Test(eEnabled))
174 {
175 m_enabled = incoming.m_enabled;
176 m_set_flags.Set(eEnabled);
177 }
178 if (incoming.m_set_flags.Test(eOneShot))
179 {
180 m_one_shot = incoming.m_one_shot;
181 m_set_flags.Set(eOneShot);
182 }
183 if (incoming.m_set_flags.Test(eCallback))
184 {
185 m_callback = incoming.m_callback;
186 m_callback_baton_sp = incoming.m_callback_baton_sp;
187 m_callback_is_synchronous = incoming.m_callback_is_synchronous;
188 m_baton_is_command_baton = incoming.m_baton_is_command_baton;
189 m_set_flags.Set(eCallback);
190 }
191 if (incoming.m_set_flags.Test(eIgnoreCount))
192 {
193 m_ignore_count = incoming.m_ignore_count;
194 m_set_flags.Set(eIgnoreCount);
195 }
196 if (incoming.m_set_flags.Test(eCondition))
197 {
198 // If we're copying over an empty condition, mark it as unset.
199 if (incoming.m_condition_text.empty()) {
200 m_condition_text.clear();
201 m_condition_text_hash = 0;
202 m_set_flags.Clear(eCondition);
203 } else {
204 m_condition_text = incoming.m_condition_text;
205 m_condition_text_hash = incoming.m_condition_text_hash;
206 m_set_flags.Set(eCondition);
207 }
208 }
209 if (incoming.m_set_flags.Test(eAutoContinue))
210 {
211 m_auto_continue = incoming.m_auto_continue;
212 m_set_flags.Set(eAutoContinue);
213 }
214 if (incoming.m_set_flags.Test(eThreadSpec) && incoming.m_thread_spec_up) {
215 if (!m_thread_spec_up)
216 m_thread_spec_up =
217 std::make_unique<ThreadSpec>(*incoming.m_thread_spec_up);
218 else
219 *m_thread_spec_up = *incoming.m_thread_spec_up;
220 m_set_flags.Set(eThreadSpec);
221 }
222}
223
224// Destructor
225BreakpointOptions::~BreakpointOptions() = default;
226
227std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
228 Target &target, const StructuredData::Dictionary &options_dict,
229 Status &error) {
230 bool enabled = true;
231 bool one_shot = false;
232 bool auto_continue = false;
233 int32_t ignore_count = 0;
234 llvm::StringRef condition_ref("");
235 Flags set_options;
236
237 const char *key = GetKey(OptionNames::EnabledState);
238 bool success;
239 if (key && options_dict.HasKey(key)) {
240 success = options_dict.GetValueForKeyAsBoolean(key, enabled);
241 if (!success) {
242 error.SetErrorStringWithFormat("%s key is not a boolean.", key);
243 return nullptr;
244 }
245 set_options.Set(eEnabled);
246 }
247
248 key = GetKey(OptionNames::OneShotState);
249 if (key && options_dict.HasKey(key)) {
250 success = options_dict.GetValueForKeyAsBoolean(key, one_shot);
251 if (!success) {
252 error.SetErrorStringWithFormat("%s key is not a boolean.", key);
253 return nullptr;
254 }
255 set_options.Set(eOneShot);
256 }
257
258 key = GetKey(OptionNames::AutoContinue);
259 if (key && options_dict.HasKey(key)) {
260 success = options_dict.GetValueForKeyAsBoolean(key, auto_continue);
261 if (!success) {
262 error.SetErrorStringWithFormat("%s key is not a boolean.", key);
263 return nullptr;
264 }
265 set_options.Set(eAutoContinue);
266 }
267
268 key = GetKey(OptionNames::IgnoreCount);
269 if (key && options_dict.HasKey(key)) {
270 success = options_dict.GetValueForKeyAsInteger(key, ignore_count);
271 if (!success) {
272 error.SetErrorStringWithFormat("%s key is not an integer.", key);
273 return nullptr;
274 }
275 set_options.Set(eIgnoreCount);
276 }
277
278 key = GetKey(OptionNames::ConditionText);
279 if (key && options_dict.HasKey(key)) {
280 success = options_dict.GetValueForKeyAsString(key, condition_ref);
281 if (!success) {
282 error.SetErrorStringWithFormat("%s key is not an string.", key);
283 return nullptr;
284 }
285 set_options.Set(eCondition);
286 }
287
288 std::unique_ptr<CommandData> cmd_data_up;
289 StructuredData::Dictionary *cmds_dict;
290 success = options_dict.GetValueForKeyAsDictionary(
291 CommandData::GetSerializationKey(), cmds_dict);
292 if (success && cmds_dict) {
293 Status cmds_error;
294 cmd_data_up = CommandData::CreateFromStructuredData(*cmds_dict, cmds_error);
295 if (cmds_error.Fail()) {
296 error.SetErrorStringWithFormat(
297 "Failed to deserialize breakpoint command options: %s.",
298 cmds_error.AsCString());
299 return nullptr;
300 }
301 }
302
303 auto bp_options = std::make_unique<BreakpointOptions>(
304 condition_ref.str().c_str(), enabled,
305 ignore_count, one_shot, auto_continue);
306 if (cmd_data_up) {
307 if (cmd_data_up->interpreter == eScriptLanguageNone)
308 bp_options->SetCommandDataCallback(cmd_data_up);
309 else {
310 ScriptInterpreter *interp = target.GetDebugger().GetScriptInterpreter();
311 if (!interp) {
312 error.SetErrorString(
313 "Can't set script commands - no script interpreter");
314 return nullptr;
315 }
316 if (interp->GetLanguage() != cmd_data_up->interpreter) {
317 error.SetErrorStringWithFormat(
318 "Current script language doesn't match breakpoint's language: %s",
319 ScriptInterpreter::LanguageToString(cmd_data_up->interpreter)
320 .c_str());
321 return nullptr;
322 }
323 Status script_error;
324 script_error =
325 interp->SetBreakpointCommandCallback(*bp_options, cmd_data_up);
326 if (script_error.Fail()) {
327 error.SetErrorStringWithFormat("Error generating script callback: %s.",
328 error.AsCString());
329 return nullptr;
330 }
331 }
332 }
333
334 StructuredData::Dictionary *thread_spec_dict;
335 success = options_dict.GetValueForKeyAsDictionary(
336 ThreadSpec::GetSerializationKey(), thread_spec_dict);
337 if (success) {
338 Status thread_spec_error;
339 std::unique_ptr<ThreadSpec> thread_spec_up =
340 ThreadSpec::CreateFromStructuredData(*thread_spec_dict,
341 thread_spec_error);
342 if (thread_spec_error.Fail()) {
343 error.SetErrorStringWithFormat(
344 "Failed to deserialize breakpoint thread spec options: %s.",
345 thread_spec_error.AsCString());
346 return nullptr;
347 }
348 bp_options->SetThreadSpec(thread_spec_up);
349 }
350 return bp_options;
351}
352
353StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() {
354 StructuredData::DictionarySP options_dict_sp(
355 new StructuredData::Dictionary());
356 if (m_set_flags.Test(eEnabled))
357 options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState),
358 m_enabled);
359 if (m_set_flags.Test(eOneShot))
360 options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState),
361 m_one_shot);
362 if (m_set_flags.Test(eAutoContinue))
363 options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue),
364 m_auto_continue);
365 if (m_set_flags.Test(eIgnoreCount))
366 options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount),
367 m_ignore_count);
368 if (m_set_flags.Test(eCondition))
369 options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText),
370 m_condition_text);
371
372 if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) {
373 auto cmd_baton =
374 std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
375 StructuredData::ObjectSP commands_sp =
376 cmd_baton->getItem()->SerializeToStructuredData();
377 if (commands_sp) {
378 options_dict_sp->AddItem(
379 BreakpointOptions::CommandData::GetSerializationKey(), commands_sp);
380 }
381 }
382 if (m_set_flags.Test(eThreadSpec) && m_thread_spec_up) {
383 StructuredData::ObjectSP thread_spec_sp =
384 m_thread_spec_up->SerializeToStructuredData();
385 options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), thread_spec_sp);
386 }
387
388 return options_dict_sp;
389}
390
391// Callbacks
392void BreakpointOptions::SetCallback(BreakpointHitCallback callback,
393 const lldb::BatonSP &callback_baton_sp,
394 bool callback_is_synchronous) {
395 // FIXME: This seems unsafe. If BatonSP actually *is* a CommandBaton, but
396 // in a shared_ptr<Baton> instead of a shared_ptr<CommandBaton>, then we will
397 // set m_baton_is_command_baton to false, which is incorrect. One possible
398 // solution is to make the base Baton class provide a method such as:
399 // virtual StringRef getBatonId() const { return ""; }
400 // and have CommandBaton override this to return something unique, and then
401 // check for it here. Another option might be to make Baton using the llvm
402 // casting infrastructure, so that we could write something like:
403 // if (llvm::isa<CommandBaton>(callback_baton_sp))
404 // at relevant callsites instead of storing a boolean.
405 m_callback_is_synchronous = callback_is_synchronous;
406 m_callback = callback;
407 m_callback_baton_sp = callback_baton_sp;
408 m_baton_is_command_baton = false;
409 m_set_flags.Set(eCallback);
410}
411
412void BreakpointOptions::SetCallback(
413 BreakpointHitCallback callback,
414 const BreakpointOptions::CommandBatonSP &callback_baton_sp,
415 bool callback_is_synchronous) {
416 m_callback_is_synchronous = callback_is_synchronous;
417 m_callback = callback;
418 m_callback_baton_sp = callback_baton_sp;
419 m_baton_is_command_baton = true;
420 m_set_flags.Set(eCallback);
421}
422
423void BreakpointOptions::ClearCallback() {
424 m_callback = BreakpointOptions::NullCallback;
425 m_callback_is_synchronous = false;
426 m_callback_baton_sp.reset();
427 m_baton_is_command_baton = false;
428 m_set_flags.Clear(eCallback);
429}
430
431Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
432
433const Baton *BreakpointOptions::GetBaton() const {
434 return m_callback_baton_sp.get();
435}
436
437bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context,
438 lldb::user_id_t break_id,
439 lldb::user_id_t break_loc_id) {
440 if (m_callback) {
441 if (context->is_synchronous == IsCallbackSynchronous()) {
442 return m_callback(m_callback_baton_sp ? m_callback_baton_sp->data()
443 : nullptr,
444 context, break_id, break_loc_id);
445 } else if (IsCallbackSynchronous()) {
446 return false;
447 }
448 }
449 return true;
450}
451
452bool BreakpointOptions::HasCallback() const {
453 return m_callback != BreakpointOptions::NullCallback;
454}
455
456bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) {
457 if (!HasCallback())
458 return false;
459 if (!m_baton_is_command_baton)
460 return false;
461
462 auto cmd_baton = std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
463 CommandData *data = cmd_baton->getItem();
464 if (!data)
465 return false;
466 command_list = data->user_source;
467 return true;
468}
469
470void BreakpointOptions::SetCondition(const char *condition) {
471 if (!condition || condition[0] == '\0') {
472 condition = "";
473 m_set_flags.Clear(eCondition);
474 }
475 else
476 m_set_flags.Set(eCondition);
477
478 m_condition_text.assign(condition);
479 std::hash<std::string> hasher;
480 m_condition_text_hash = hasher(m_condition_text);
481}
482
483const char *BreakpointOptions::GetConditionText(size_t *hash) const {
484 if (!m_condition_text.empty()) {
485 if (hash)
486 *hash = m_condition_text_hash;
487
488 return m_condition_text.c_str();
489 } else {
490 return nullptr;
491 }
492}
493
494const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const {
495 return m_thread_spec_up.get();
496}
497
498ThreadSpec *BreakpointOptions::GetThreadSpec() {
499 if (m_thread_spec_up == nullptr) {
500 m_set_flags.Set(eThreadSpec);
501 m_thread_spec_up = std::make_unique<ThreadSpec>();
502 }
503
504 return m_thread_spec_up.get();
505}
506
507void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) {
508 GetThreadSpec()->SetTID(thread_id);
509 m_set_flags.Set(eThreadSpec);
510}
511
512void BreakpointOptions::SetThreadSpec(
513 std::unique_ptr<ThreadSpec> &thread_spec_up) {
514 m_thread_spec_up = std::move(thread_spec_up);
515 m_set_flags.Set(eThreadSpec);
516}
517
518void BreakpointOptions::GetDescription(Stream *s,
519 lldb::DescriptionLevel level) const {
520 // Figure out if there are any options not at their default value, and only
521 // print anything if there are:
522
523 if (m_ignore_count != 0 || !m_enabled || m_one_shot || m_auto_continue ||
524 (GetThreadSpecNoCreate() != nullptr &&
525 GetThreadSpecNoCreate()->HasSpecification())) {
526 if (level == lldb::eDescriptionLevelVerbose) {
527 s->EOL();
528 s->IndentMore();
529 s->Indent();
530 s->PutCString("Breakpoint Options:\n");
531 s->IndentMore();
532 s->Indent();
533 } else
534 s->PutCString(" Options: ");
535
536 if (m_ignore_count > 0)
537 s->Printf("ignore: %d ", m_ignore_count);
538 s->Printf("%sabled ", m_enabled ? "en" : "dis");
539
540 if (m_one_shot)
541 s->Printf("one-shot ");
542
543 if (m_auto_continue)
544 s->Printf("auto-continue ");
545
546 if (m_thread_spec_up)
547 m_thread_spec_up->GetDescription(s, level);
548
549 if (level == lldb::eDescriptionLevelFull) {
550 s->IndentLess();
551 s->IndentMore();
552 }
553 }
554
555 if (m_callback_baton_sp.get()) {
556 if (level != eDescriptionLevelBrief) {
557 s->EOL();
558 m_callback_baton_sp->GetDescription(s->AsRawOstream(), level,
559 s->GetIndentLevel());
560 }
561 }
562 if (!m_condition_text.empty()) {
563 if (level != eDescriptionLevelBrief) {
564 s->EOL();
565 s->Printf("Condition: %s\n", m_condition_text.c_str());
566 }
567 }
568}
569
570void BreakpointOptions::CommandBaton::GetDescription(
571 llvm::raw_ostream &s, lldb::DescriptionLevel level,
572 unsigned indentation) const {
573 const CommandData *data = getItem();
574
575 if (level == eDescriptionLevelBrief) {
576 s << ", commands = "
577 << ((data && data->user_source.GetSize() > 0) ? "yes" : "no");
578 return;
579 }
580
581 indentation += 2;
582 s.indent(indentation);
583 s << "Breakpoint commands";
584 if (data->interpreter != eScriptLanguageNone)
585 s << llvm::formatv(" ({0}):\n",
586 ScriptInterpreter::LanguageToString(data->interpreter));
587 else
588 s << ":\n";
589
590 indentation += 2;
591 if (data && data->user_source.GetSize() > 0) {
592 for (llvm::StringRef str : data->user_source) {
593 s.indent(indentation);
594 s << str << "\n";
595 }
596 } else
597 s << "No commands.\n";
598}
599
600void BreakpointOptions::SetCommandDataCallback(
601 std::unique_ptr<CommandData> &cmd_data) {
602 cmd_data->interpreter = eScriptLanguageNone;
603 auto baton_sp = std::make_shared<CommandBaton>(std::move(cmd_data));
604 SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, baton_sp);
605 m_set_flags.Set(eCallback);
606}
607
608bool BreakpointOptions::BreakpointOptionsCallbackFunction(
609 void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
610 lldb::user_id_t break_loc_id) {
611 bool ret_value = true;
612 if (baton == nullptr)
613 return true;
614
615 CommandData *data = (CommandData *)baton;
616 StringList &commands = data->user_source;
617
618 if (commands.GetSize() > 0) {
619 ExecutionContext exe_ctx(context->exe_ctx_ref);
620 Target *target = exe_ctx.GetTargetPtr();
621 if (target) {
622 Debugger &debugger = target->GetDebugger();
623 CommandReturnObject result(debugger.GetUseColor());
624
625 // Rig up the results secondary output stream to the debugger's, so the
626 // output will come out synchronously if the debugger is set up that way.
627 StreamSP output_stream(debugger.GetAsyncOutputStream());
628 StreamSP error_stream(debugger.GetAsyncErrorStream());
629 result.SetImmediateOutputStream(output_stream);
630 result.SetImmediateErrorStream(error_stream);
631
632 CommandInterpreterRunOptions options;
633 options.SetStopOnContinue(true);
634 options.SetStopOnError(data->stop_on_error);
635 options.SetEchoCommands(true);
636 options.SetPrintResults(true);
637 options.SetPrintErrors(true);
638 options.SetAddToHistory(false);
639
640 debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx,
641 options, result);
642 result.GetImmediateOutputStream()->Flush();
643 result.GetImmediateErrorStream()->Flush();
644 }
645 }
646 return ret_value;
647}
648
649void BreakpointOptions::Clear()
650{
651 m_set_flags.Clear();
652 m_thread_spec_up.release();
653 m_one_shot = false;
654 m_ignore_count = 0;
655 m_auto_continue = false;
656 m_callback = nullptr;
657 m_callback_baton_sp.reset();
658 m_baton_is_command_baton = false;
659 m_callback_is_synchronous = false;
660 m_enabled = false;
661 m_condition_text.clear();
662}