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