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