xref: /openbsd-src/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- BreakpointOptions.cpp ---------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Breakpoint/BreakpointOptions.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Breakpoint/StoppointCallbackContext.h"
12061da546Spatrick #include "lldb/Core/Value.h"
13061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
14061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
15061da546Spatrick #include "lldb/Target/Process.h"
16061da546Spatrick #include "lldb/Target/Target.h"
17061da546Spatrick #include "lldb/Target/ThreadSpec.h"
18061da546Spatrick #include "lldb/Utility/Stream.h"
19061da546Spatrick #include "lldb/Utility/StringList.h"
20061da546Spatrick 
21061da546Spatrick #include "llvm/ADT/STLExtras.h"
22061da546Spatrick 
23061da546Spatrick using namespace lldb;
24061da546Spatrick using namespace lldb_private;
25061da546Spatrick 
26061da546Spatrick const char
27061da546Spatrick     *BreakpointOptions::CommandData::g_option_names[static_cast<uint32_t>(
28061da546Spatrick         BreakpointOptions::CommandData::OptionNames::LastOptionName)]{
29061da546Spatrick         "UserSource", "ScriptSource", "StopOnError"};
30061da546Spatrick 
31061da546Spatrick StructuredData::ObjectSP
SerializeToStructuredData()32061da546Spatrick BreakpointOptions::CommandData::SerializeToStructuredData() {
33061da546Spatrick   size_t num_strings = user_source.GetSize();
34061da546Spatrick   if (num_strings == 0 && script_source.empty()) {
35061da546Spatrick     // We shouldn't serialize commands if there aren't any, return an empty sp
36061da546Spatrick     // to indicate this.
37061da546Spatrick     return StructuredData::ObjectSP();
38061da546Spatrick   }
39061da546Spatrick 
40061da546Spatrick   StructuredData::DictionarySP options_dict_sp(
41061da546Spatrick       new StructuredData::Dictionary());
42061da546Spatrick   options_dict_sp->AddBooleanItem(GetKey(OptionNames::StopOnError),
43061da546Spatrick                                   stop_on_error);
44061da546Spatrick 
45061da546Spatrick   StructuredData::ArraySP user_source_sp(new StructuredData::Array());
46061da546Spatrick   for (size_t i = 0; i < num_strings; i++) {
47061da546Spatrick     StructuredData::StringSP item_sp(
48061da546Spatrick         new StructuredData::String(user_source[i]));
49061da546Spatrick     user_source_sp->AddItem(item_sp);
50061da546Spatrick     options_dict_sp->AddItem(GetKey(OptionNames::UserSource), user_source_sp);
51061da546Spatrick   }
52061da546Spatrick 
53061da546Spatrick   options_dict_sp->AddStringItem(
54061da546Spatrick       GetKey(OptionNames::Interpreter),
55061da546Spatrick       ScriptInterpreter::LanguageToString(interpreter));
56061da546Spatrick   return options_dict_sp;
57061da546Spatrick }
58061da546Spatrick 
59061da546Spatrick std::unique_ptr<BreakpointOptions::CommandData>
CreateFromStructuredData(const StructuredData::Dictionary & options_dict,Status & error)60061da546Spatrick BreakpointOptions::CommandData::CreateFromStructuredData(
61061da546Spatrick     const StructuredData::Dictionary &options_dict, Status &error) {
62061da546Spatrick   std::unique_ptr<CommandData> data_up(new CommandData());
63061da546Spatrick 
64061da546Spatrick   bool success = options_dict.GetValueForKeyAsBoolean(
65061da546Spatrick       GetKey(OptionNames::StopOnError), data_up->stop_on_error);
66061da546Spatrick 
67061da546Spatrick   llvm::StringRef interpreter_str;
68061da546Spatrick   ScriptLanguage interp_language;
69061da546Spatrick   success = options_dict.GetValueForKeyAsString(
70061da546Spatrick       GetKey(OptionNames::Interpreter), interpreter_str);
71061da546Spatrick 
72061da546Spatrick   if (!success) {
73061da546Spatrick     error.SetErrorString("Missing command language value.");
74061da546Spatrick     return data_up;
75061da546Spatrick   }
76061da546Spatrick 
77061da546Spatrick   interp_language = ScriptInterpreter::StringToLanguage(interpreter_str);
78061da546Spatrick   if (interp_language == eScriptLanguageUnknown) {
79061da546Spatrick     error.SetErrorStringWithFormatv("Unknown breakpoint command language: {0}.",
80061da546Spatrick                                     interpreter_str);
81061da546Spatrick     return data_up;
82061da546Spatrick   }
83061da546Spatrick   data_up->interpreter = interp_language;
84061da546Spatrick 
85061da546Spatrick   StructuredData::Array *user_source;
86061da546Spatrick   success = options_dict.GetValueForKeyAsArray(GetKey(OptionNames::UserSource),
87061da546Spatrick                                                user_source);
88061da546Spatrick   if (success) {
89061da546Spatrick     size_t num_elems = user_source->GetSize();
90061da546Spatrick     for (size_t i = 0; i < num_elems; i++) {
91061da546Spatrick       llvm::StringRef elem_string;
92061da546Spatrick       success = user_source->GetItemAtIndexAsString(i, elem_string);
93061da546Spatrick       if (success)
94061da546Spatrick         data_up->user_source.AppendString(elem_string);
95061da546Spatrick     }
96061da546Spatrick   }
97061da546Spatrick 
98061da546Spatrick   return data_up;
99061da546Spatrick }
100061da546Spatrick 
101061da546Spatrick const char *BreakpointOptions::g_option_names[(
102061da546Spatrick     size_t)BreakpointOptions::OptionNames::LastOptionName]{
103061da546Spatrick     "ConditionText", "IgnoreCount",
104061da546Spatrick     "EnabledState", "OneShotState", "AutoContinue"};
105061da546Spatrick 
NullCallback(void * baton,StoppointCallbackContext * context,lldb::user_id_t break_id,lldb::user_id_t break_loc_id)106061da546Spatrick bool BreakpointOptions::NullCallback(void *baton,
107061da546Spatrick                                      StoppointCallbackContext *context,
108061da546Spatrick                                      lldb::user_id_t break_id,
109061da546Spatrick                                      lldb::user_id_t break_loc_id) {
110061da546Spatrick   return true;
111061da546Spatrick }
112061da546Spatrick 
113061da546Spatrick // BreakpointOptions constructor
BreakpointOptions(bool all_flags_set)114061da546Spatrick BreakpointOptions::BreakpointOptions(bool all_flags_set)
115*f6aab3d8Srobert     : m_callback(BreakpointOptions::NullCallback),
116061da546Spatrick       m_baton_is_command_baton(false), m_callback_is_synchronous(false),
117*f6aab3d8Srobert       m_enabled(true), m_one_shot(false), m_ignore_count(0),
118*f6aab3d8Srobert       m_condition_text_hash(0), m_inject_condition(false),
119*f6aab3d8Srobert       m_auto_continue(false), m_set_flags(0) {
120061da546Spatrick   if (all_flags_set)
121061da546Spatrick     m_set_flags.Set(~((Flags::ValueType)0));
122061da546Spatrick }
123061da546Spatrick 
BreakpointOptions(const char * condition,bool enabled,int32_t ignore,bool one_shot,bool auto_continue)124061da546Spatrick BreakpointOptions::BreakpointOptions(const char *condition, bool enabled,
125061da546Spatrick                                      int32_t ignore, bool one_shot,
126061da546Spatrick                                      bool auto_continue)
127061da546Spatrick     : m_callback(nullptr), m_baton_is_command_baton(false),
128061da546Spatrick       m_callback_is_synchronous(false), m_enabled(enabled),
129*f6aab3d8Srobert       m_one_shot(one_shot), m_ignore_count(ignore), m_condition_text_hash(0),
130*f6aab3d8Srobert       m_inject_condition(false), m_auto_continue(auto_continue) {
131*f6aab3d8Srobert   m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot | eAutoContinue);
132061da546Spatrick     if (condition && *condition != '\0') {
133061da546Spatrick       SetCondition(condition);
134061da546Spatrick     }
135061da546Spatrick }
136061da546Spatrick 
137061da546Spatrick // BreakpointOptions copy constructor
BreakpointOptions(const BreakpointOptions & rhs)138061da546Spatrick BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs)
139061da546Spatrick     : m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp),
140061da546Spatrick       m_baton_is_command_baton(rhs.m_baton_is_command_baton),
141061da546Spatrick       m_callback_is_synchronous(rhs.m_callback_is_synchronous),
142061da546Spatrick       m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot),
143*f6aab3d8Srobert       m_ignore_count(rhs.m_ignore_count), m_inject_condition(false),
144061da546Spatrick       m_auto_continue(rhs.m_auto_continue), m_set_flags(rhs.m_set_flags) {
145061da546Spatrick   if (rhs.m_thread_spec_up != nullptr)
146dda28197Spatrick     m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
147061da546Spatrick   m_condition_text = rhs.m_condition_text;
148061da546Spatrick   m_condition_text_hash = rhs.m_condition_text_hash;
149061da546Spatrick }
150061da546Spatrick 
151061da546Spatrick // BreakpointOptions assignment operator
152061da546Spatrick const BreakpointOptions &BreakpointOptions::
operator =(const BreakpointOptions & rhs)153061da546Spatrick operator=(const BreakpointOptions &rhs) {
154061da546Spatrick   m_callback = rhs.m_callback;
155061da546Spatrick   m_callback_baton_sp = rhs.m_callback_baton_sp;
156061da546Spatrick   m_baton_is_command_baton = rhs.m_baton_is_command_baton;
157061da546Spatrick   m_callback_is_synchronous = rhs.m_callback_is_synchronous;
158061da546Spatrick   m_enabled = rhs.m_enabled;
159061da546Spatrick   m_one_shot = rhs.m_one_shot;
160061da546Spatrick   m_ignore_count = rhs.m_ignore_count;
161061da546Spatrick   if (rhs.m_thread_spec_up != nullptr)
162dda28197Spatrick     m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
163061da546Spatrick   m_condition_text = rhs.m_condition_text;
164061da546Spatrick   m_condition_text_hash = rhs.m_condition_text_hash;
165*f6aab3d8Srobert   m_inject_condition = rhs.m_inject_condition;
166061da546Spatrick   m_auto_continue = rhs.m_auto_continue;
167061da546Spatrick   m_set_flags = rhs.m_set_flags;
168061da546Spatrick   return *this;
169061da546Spatrick }
170061da546Spatrick 
CopyOverSetOptions(const BreakpointOptions & incoming)171061da546Spatrick void BreakpointOptions::CopyOverSetOptions(const BreakpointOptions &incoming)
172061da546Spatrick {
173061da546Spatrick   if (incoming.m_set_flags.Test(eEnabled))
174061da546Spatrick   {
175061da546Spatrick     m_enabled = incoming.m_enabled;
176061da546Spatrick     m_set_flags.Set(eEnabled);
177061da546Spatrick   }
178061da546Spatrick   if (incoming.m_set_flags.Test(eOneShot))
179061da546Spatrick   {
180061da546Spatrick     m_one_shot = incoming.m_one_shot;
181061da546Spatrick     m_set_flags.Set(eOneShot);
182061da546Spatrick   }
183061da546Spatrick   if (incoming.m_set_flags.Test(eCallback))
184061da546Spatrick   {
185061da546Spatrick     m_callback = incoming.m_callback;
186061da546Spatrick     m_callback_baton_sp = incoming.m_callback_baton_sp;
187061da546Spatrick     m_callback_is_synchronous = incoming.m_callback_is_synchronous;
188061da546Spatrick     m_baton_is_command_baton = incoming.m_baton_is_command_baton;
189061da546Spatrick     m_set_flags.Set(eCallback);
190061da546Spatrick   }
191061da546Spatrick   if (incoming.m_set_flags.Test(eIgnoreCount))
192061da546Spatrick   {
193061da546Spatrick     m_ignore_count = incoming.m_ignore_count;
194061da546Spatrick     m_set_flags.Set(eIgnoreCount);
195061da546Spatrick   }
196061da546Spatrick   if (incoming.m_set_flags.Test(eCondition))
197061da546Spatrick   {
198061da546Spatrick     // If we're copying over an empty condition, mark it as unset.
199061da546Spatrick     if (incoming.m_condition_text.empty()) {
200061da546Spatrick       m_condition_text.clear();
201061da546Spatrick       m_condition_text_hash = 0;
202061da546Spatrick       m_set_flags.Clear(eCondition);
203061da546Spatrick     } else {
204061da546Spatrick       m_condition_text = incoming.m_condition_text;
205061da546Spatrick       m_condition_text_hash = incoming.m_condition_text_hash;
206061da546Spatrick       m_set_flags.Set(eCondition);
207061da546Spatrick     }
208061da546Spatrick   }
209061da546Spatrick   if (incoming.m_set_flags.Test(eAutoContinue))
210061da546Spatrick   {
211061da546Spatrick     m_auto_continue = incoming.m_auto_continue;
212061da546Spatrick     m_set_flags.Set(eAutoContinue);
213061da546Spatrick   }
214061da546Spatrick   if (incoming.m_set_flags.Test(eThreadSpec) && incoming.m_thread_spec_up) {
215061da546Spatrick     if (!m_thread_spec_up)
216dda28197Spatrick       m_thread_spec_up =
217dda28197Spatrick           std::make_unique<ThreadSpec>(*incoming.m_thread_spec_up);
218061da546Spatrick     else
219061da546Spatrick       *m_thread_spec_up = *incoming.m_thread_spec_up;
220061da546Spatrick     m_set_flags.Set(eThreadSpec);
221061da546Spatrick   }
222061da546Spatrick }
223061da546Spatrick 
224061da546Spatrick // Destructor
225061da546Spatrick BreakpointOptions::~BreakpointOptions() = default;
226061da546Spatrick 
CreateFromStructuredData(Target & target,const StructuredData::Dictionary & options_dict,Status & error)227061da546Spatrick std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
228061da546Spatrick     Target &target, const StructuredData::Dictionary &options_dict,
229061da546Spatrick     Status &error) {
230061da546Spatrick   bool enabled = true;
231061da546Spatrick   bool one_shot = false;
232061da546Spatrick   bool auto_continue = false;
233061da546Spatrick   int32_t ignore_count = 0;
234061da546Spatrick   llvm::StringRef condition_ref("");
235061da546Spatrick   Flags set_options;
236061da546Spatrick 
237061da546Spatrick   const char *key = GetKey(OptionNames::EnabledState);
238061da546Spatrick   bool success;
239061da546Spatrick   if (key && options_dict.HasKey(key)) {
240061da546Spatrick     success = options_dict.GetValueForKeyAsBoolean(key, enabled);
241061da546Spatrick     if (!success) {
242061da546Spatrick       error.SetErrorStringWithFormat("%s key is not a boolean.", key);
243061da546Spatrick       return nullptr;
244061da546Spatrick     }
245061da546Spatrick     set_options.Set(eEnabled);
246061da546Spatrick   }
247061da546Spatrick 
248061da546Spatrick   key = GetKey(OptionNames::OneShotState);
249061da546Spatrick   if (key && options_dict.HasKey(key)) {
250061da546Spatrick     success = options_dict.GetValueForKeyAsBoolean(key, one_shot);
251061da546Spatrick     if (!success) {
252061da546Spatrick       error.SetErrorStringWithFormat("%s key is not a boolean.", key);
253061da546Spatrick       return nullptr;
254061da546Spatrick       }
255061da546Spatrick       set_options.Set(eOneShot);
256061da546Spatrick   }
257061da546Spatrick 
258061da546Spatrick   key = GetKey(OptionNames::AutoContinue);
259061da546Spatrick   if (key && options_dict.HasKey(key)) {
260061da546Spatrick     success = options_dict.GetValueForKeyAsBoolean(key, auto_continue);
261061da546Spatrick     if (!success) {
262061da546Spatrick       error.SetErrorStringWithFormat("%s key is not a boolean.", key);
263061da546Spatrick       return nullptr;
264061da546Spatrick       }
265061da546Spatrick       set_options.Set(eAutoContinue);
266061da546Spatrick   }
267061da546Spatrick 
268061da546Spatrick   key = GetKey(OptionNames::IgnoreCount);
269061da546Spatrick   if (key && options_dict.HasKey(key)) {
270061da546Spatrick     success = options_dict.GetValueForKeyAsInteger(key, ignore_count);
271061da546Spatrick     if (!success) {
272061da546Spatrick       error.SetErrorStringWithFormat("%s key is not an integer.", key);
273061da546Spatrick       return nullptr;
274061da546Spatrick     }
275061da546Spatrick     set_options.Set(eIgnoreCount);
276061da546Spatrick   }
277061da546Spatrick 
278061da546Spatrick   key = GetKey(OptionNames::ConditionText);
279061da546Spatrick   if (key && options_dict.HasKey(key)) {
280061da546Spatrick     success = options_dict.GetValueForKeyAsString(key, condition_ref);
281061da546Spatrick     if (!success) {
282061da546Spatrick       error.SetErrorStringWithFormat("%s key is not an string.", key);
283061da546Spatrick       return nullptr;
284061da546Spatrick     }
285061da546Spatrick     set_options.Set(eCondition);
286061da546Spatrick   }
287061da546Spatrick 
288061da546Spatrick   std::unique_ptr<CommandData> cmd_data_up;
289061da546Spatrick   StructuredData::Dictionary *cmds_dict;
290061da546Spatrick   success = options_dict.GetValueForKeyAsDictionary(
291061da546Spatrick       CommandData::GetSerializationKey(), cmds_dict);
292061da546Spatrick   if (success && cmds_dict) {
293061da546Spatrick     Status cmds_error;
294061da546Spatrick     cmd_data_up = CommandData::CreateFromStructuredData(*cmds_dict, cmds_error);
295061da546Spatrick     if (cmds_error.Fail()) {
296061da546Spatrick       error.SetErrorStringWithFormat(
297061da546Spatrick           "Failed to deserialize breakpoint command options: %s.",
298061da546Spatrick           cmds_error.AsCString());
299061da546Spatrick       return nullptr;
300061da546Spatrick     }
301061da546Spatrick   }
302061da546Spatrick 
303061da546Spatrick   auto bp_options = std::make_unique<BreakpointOptions>(
304061da546Spatrick       condition_ref.str().c_str(), enabled,
305061da546Spatrick       ignore_count, one_shot, auto_continue);
306061da546Spatrick   if (cmd_data_up) {
307061da546Spatrick     if (cmd_data_up->interpreter == eScriptLanguageNone)
308061da546Spatrick       bp_options->SetCommandDataCallback(cmd_data_up);
309061da546Spatrick     else {
310061da546Spatrick       ScriptInterpreter *interp = target.GetDebugger().GetScriptInterpreter();
311061da546Spatrick       if (!interp) {
312be691f3bSpatrick         error.SetErrorString(
313061da546Spatrick             "Can't set script commands - no script interpreter");
314061da546Spatrick         return nullptr;
315061da546Spatrick       }
316061da546Spatrick       if (interp->GetLanguage() != cmd_data_up->interpreter) {
317061da546Spatrick         error.SetErrorStringWithFormat(
318061da546Spatrick             "Current script language doesn't match breakpoint's language: %s",
319061da546Spatrick             ScriptInterpreter::LanguageToString(cmd_data_up->interpreter)
320061da546Spatrick                 .c_str());
321061da546Spatrick         return nullptr;
322061da546Spatrick       }
323061da546Spatrick       Status script_error;
324061da546Spatrick       script_error =
325be691f3bSpatrick           interp->SetBreakpointCommandCallback(*bp_options, cmd_data_up);
326061da546Spatrick       if (script_error.Fail()) {
327061da546Spatrick         error.SetErrorStringWithFormat("Error generating script callback: %s.",
328061da546Spatrick                                        error.AsCString());
329061da546Spatrick         return nullptr;
330061da546Spatrick       }
331061da546Spatrick     }
332061da546Spatrick   }
333061da546Spatrick 
334061da546Spatrick   StructuredData::Dictionary *thread_spec_dict;
335061da546Spatrick   success = options_dict.GetValueForKeyAsDictionary(
336061da546Spatrick       ThreadSpec::GetSerializationKey(), thread_spec_dict);
337061da546Spatrick   if (success) {
338061da546Spatrick     Status thread_spec_error;
339061da546Spatrick     std::unique_ptr<ThreadSpec> thread_spec_up =
340061da546Spatrick         ThreadSpec::CreateFromStructuredData(*thread_spec_dict,
341061da546Spatrick                                              thread_spec_error);
342061da546Spatrick     if (thread_spec_error.Fail()) {
343061da546Spatrick       error.SetErrorStringWithFormat(
344061da546Spatrick           "Failed to deserialize breakpoint thread spec options: %s.",
345061da546Spatrick           thread_spec_error.AsCString());
346061da546Spatrick       return nullptr;
347061da546Spatrick     }
348061da546Spatrick     bp_options->SetThreadSpec(thread_spec_up);
349061da546Spatrick   }
350061da546Spatrick   return bp_options;
351061da546Spatrick }
352061da546Spatrick 
SerializeToStructuredData()353061da546Spatrick StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() {
354061da546Spatrick   StructuredData::DictionarySP options_dict_sp(
355061da546Spatrick       new StructuredData::Dictionary());
356061da546Spatrick   if (m_set_flags.Test(eEnabled))
357061da546Spatrick     options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState),
358061da546Spatrick                                     m_enabled);
359061da546Spatrick   if (m_set_flags.Test(eOneShot))
360061da546Spatrick     options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState),
361061da546Spatrick                                m_one_shot);
362061da546Spatrick   if (m_set_flags.Test(eAutoContinue))
363061da546Spatrick     options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue),
364061da546Spatrick                                m_auto_continue);
365061da546Spatrick   if (m_set_flags.Test(eIgnoreCount))
366061da546Spatrick     options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount),
367061da546Spatrick                                     m_ignore_count);
368061da546Spatrick   if (m_set_flags.Test(eCondition))
369061da546Spatrick     options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText),
370061da546Spatrick                                    m_condition_text);
371061da546Spatrick 
372061da546Spatrick   if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) {
373061da546Spatrick     auto cmd_baton =
374061da546Spatrick         std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
375061da546Spatrick     StructuredData::ObjectSP commands_sp =
376061da546Spatrick         cmd_baton->getItem()->SerializeToStructuredData();
377061da546Spatrick     if (commands_sp) {
378061da546Spatrick       options_dict_sp->AddItem(
379061da546Spatrick           BreakpointOptions::CommandData::GetSerializationKey(), commands_sp);
380061da546Spatrick     }
381061da546Spatrick   }
382061da546Spatrick   if (m_set_flags.Test(eThreadSpec) && m_thread_spec_up) {
383061da546Spatrick     StructuredData::ObjectSP thread_spec_sp =
384061da546Spatrick         m_thread_spec_up->SerializeToStructuredData();
385061da546Spatrick     options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), thread_spec_sp);
386061da546Spatrick   }
387061da546Spatrick 
388061da546Spatrick   return options_dict_sp;
389061da546Spatrick }
390061da546Spatrick 
391061da546Spatrick // Callbacks
SetCallback(BreakpointHitCallback callback,const lldb::BatonSP & callback_baton_sp,bool callback_is_synchronous)392061da546Spatrick void BreakpointOptions::SetCallback(BreakpointHitCallback callback,
393061da546Spatrick                                     const lldb::BatonSP &callback_baton_sp,
394061da546Spatrick                                     bool callback_is_synchronous) {
395061da546Spatrick   // FIXME: This seems unsafe.  If BatonSP actually *is* a CommandBaton, but
396061da546Spatrick   // in a shared_ptr<Baton> instead of a shared_ptr<CommandBaton>, then we will
397061da546Spatrick   // set m_baton_is_command_baton to false, which is incorrect. One possible
398061da546Spatrick   // solution is to make the base Baton class provide a method such as:
399061da546Spatrick   //     virtual StringRef getBatonId() const { return ""; }
400061da546Spatrick   // and have CommandBaton override this to return something unique, and then
401061da546Spatrick   // check for it here.  Another option might be to make Baton using the llvm
402061da546Spatrick   // casting infrastructure, so that we could write something like:
403061da546Spatrick   //     if (llvm::isa<CommandBaton>(callback_baton_sp))
404061da546Spatrick   // at relevant callsites instead of storing a boolean.
405061da546Spatrick   m_callback_is_synchronous = callback_is_synchronous;
406061da546Spatrick   m_callback = callback;
407061da546Spatrick   m_callback_baton_sp = callback_baton_sp;
408061da546Spatrick   m_baton_is_command_baton = false;
409061da546Spatrick   m_set_flags.Set(eCallback);
410061da546Spatrick }
411061da546Spatrick 
SetCallback(BreakpointHitCallback callback,const BreakpointOptions::CommandBatonSP & callback_baton_sp,bool callback_is_synchronous)412061da546Spatrick void BreakpointOptions::SetCallback(
413061da546Spatrick     BreakpointHitCallback callback,
414061da546Spatrick     const BreakpointOptions::CommandBatonSP &callback_baton_sp,
415061da546Spatrick     bool callback_is_synchronous) {
416061da546Spatrick   m_callback_is_synchronous = callback_is_synchronous;
417061da546Spatrick   m_callback = callback;
418061da546Spatrick   m_callback_baton_sp = callback_baton_sp;
419061da546Spatrick   m_baton_is_command_baton = true;
420061da546Spatrick   m_set_flags.Set(eCallback);
421061da546Spatrick }
422061da546Spatrick 
ClearCallback()423061da546Spatrick void BreakpointOptions::ClearCallback() {
424061da546Spatrick   m_callback = BreakpointOptions::NullCallback;
425061da546Spatrick   m_callback_is_synchronous = false;
426061da546Spatrick   m_callback_baton_sp.reset();
427061da546Spatrick   m_baton_is_command_baton = false;
428061da546Spatrick   m_set_flags.Clear(eCallback);
429061da546Spatrick }
430061da546Spatrick 
GetBaton()431061da546Spatrick Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
432061da546Spatrick 
GetBaton() const433061da546Spatrick const Baton *BreakpointOptions::GetBaton() const {
434061da546Spatrick   return m_callback_baton_sp.get();
435061da546Spatrick }
436061da546Spatrick 
InvokeCallback(StoppointCallbackContext * context,lldb::user_id_t break_id,lldb::user_id_t break_loc_id)437061da546Spatrick bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context,
438061da546Spatrick                                        lldb::user_id_t break_id,
439061da546Spatrick                                        lldb::user_id_t break_loc_id) {
440061da546Spatrick   if (m_callback) {
441061da546Spatrick     if (context->is_synchronous == IsCallbackSynchronous()) {
442061da546Spatrick         return m_callback(m_callback_baton_sp ? m_callback_baton_sp->data()
443061da546Spatrick                                           : nullptr,
444061da546Spatrick                       context, break_id, break_loc_id);
445061da546Spatrick     } else if (IsCallbackSynchronous()) {
446061da546Spatrick       return false;
447061da546Spatrick     }
448061da546Spatrick   }
449061da546Spatrick   return true;
450061da546Spatrick }
451061da546Spatrick 
HasCallback() const452061da546Spatrick bool BreakpointOptions::HasCallback() const {
453061da546Spatrick   return m_callback != BreakpointOptions::NullCallback;
454061da546Spatrick }
455061da546Spatrick 
GetCommandLineCallbacks(StringList & command_list)456061da546Spatrick bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) {
457061da546Spatrick   if (!HasCallback())
458061da546Spatrick     return false;
459061da546Spatrick   if (!m_baton_is_command_baton)
460061da546Spatrick     return false;
461061da546Spatrick 
462061da546Spatrick   auto cmd_baton = std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
463061da546Spatrick   CommandData *data = cmd_baton->getItem();
464061da546Spatrick   if (!data)
465061da546Spatrick     return false;
466061da546Spatrick   command_list = data->user_source;
467061da546Spatrick   return true;
468061da546Spatrick }
469061da546Spatrick 
SetCondition(const char * condition)470061da546Spatrick void BreakpointOptions::SetCondition(const char *condition) {
471061da546Spatrick   if (!condition || condition[0] == '\0') {
472061da546Spatrick     condition = "";
473061da546Spatrick     m_set_flags.Clear(eCondition);
474061da546Spatrick   }
475061da546Spatrick   else
476061da546Spatrick     m_set_flags.Set(eCondition);
477061da546Spatrick 
478061da546Spatrick   m_condition_text.assign(condition);
479061da546Spatrick   std::hash<std::string> hasher;
480061da546Spatrick   m_condition_text_hash = hasher(m_condition_text);
481061da546Spatrick }
482061da546Spatrick 
GetConditionText(size_t * hash) const483061da546Spatrick const char *BreakpointOptions::GetConditionText(size_t *hash) const {
484061da546Spatrick   if (!m_condition_text.empty()) {
485061da546Spatrick     if (hash)
486061da546Spatrick       *hash = m_condition_text_hash;
487061da546Spatrick 
488061da546Spatrick     return m_condition_text.c_str();
489061da546Spatrick   } else {
490061da546Spatrick     return nullptr;
491061da546Spatrick   }
492061da546Spatrick }
493061da546Spatrick 
GetThreadSpecNoCreate() const494061da546Spatrick const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const {
495061da546Spatrick   return m_thread_spec_up.get();
496061da546Spatrick }
497061da546Spatrick 
GetThreadSpec()498061da546Spatrick ThreadSpec *BreakpointOptions::GetThreadSpec() {
499061da546Spatrick   if (m_thread_spec_up == nullptr) {
500061da546Spatrick     m_set_flags.Set(eThreadSpec);
501dda28197Spatrick     m_thread_spec_up = std::make_unique<ThreadSpec>();
502061da546Spatrick   }
503061da546Spatrick 
504061da546Spatrick   return m_thread_spec_up.get();
505061da546Spatrick }
506061da546Spatrick 
SetThreadID(lldb::tid_t thread_id)507061da546Spatrick void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) {
508061da546Spatrick   GetThreadSpec()->SetTID(thread_id);
509061da546Spatrick   m_set_flags.Set(eThreadSpec);
510061da546Spatrick }
511061da546Spatrick 
SetThreadSpec(std::unique_ptr<ThreadSpec> & thread_spec_up)512061da546Spatrick void BreakpointOptions::SetThreadSpec(
513061da546Spatrick     std::unique_ptr<ThreadSpec> &thread_spec_up) {
514061da546Spatrick   m_thread_spec_up = std::move(thread_spec_up);
515061da546Spatrick   m_set_flags.Set(eThreadSpec);
516061da546Spatrick }
517061da546Spatrick 
GetDescription(Stream * s,lldb::DescriptionLevel level) const518061da546Spatrick void BreakpointOptions::GetDescription(Stream *s,
519061da546Spatrick                                        lldb::DescriptionLevel level) const {
520061da546Spatrick   // Figure out if there are any options not at their default value, and only
521061da546Spatrick   // print anything if there are:
522061da546Spatrick 
523061da546Spatrick   if (m_ignore_count != 0 || !m_enabled || m_one_shot || m_auto_continue ||
524061da546Spatrick       (GetThreadSpecNoCreate() != nullptr &&
525061da546Spatrick        GetThreadSpecNoCreate()->HasSpecification())) {
526061da546Spatrick     if (level == lldb::eDescriptionLevelVerbose) {
527061da546Spatrick       s->EOL();
528061da546Spatrick       s->IndentMore();
529061da546Spatrick       s->Indent();
530061da546Spatrick       s->PutCString("Breakpoint Options:\n");
531061da546Spatrick       s->IndentMore();
532061da546Spatrick       s->Indent();
533061da546Spatrick     } else
534061da546Spatrick       s->PutCString(" Options: ");
535061da546Spatrick 
536061da546Spatrick     if (m_ignore_count > 0)
537061da546Spatrick       s->Printf("ignore: %d ", m_ignore_count);
538061da546Spatrick     s->Printf("%sabled ", m_enabled ? "en" : "dis");
539061da546Spatrick 
540061da546Spatrick     if (m_one_shot)
541061da546Spatrick       s->Printf("one-shot ");
542061da546Spatrick 
543061da546Spatrick     if (m_auto_continue)
544061da546Spatrick       s->Printf("auto-continue ");
545061da546Spatrick 
546061da546Spatrick     if (m_thread_spec_up)
547061da546Spatrick       m_thread_spec_up->GetDescription(s, level);
548061da546Spatrick 
549061da546Spatrick     if (level == lldb::eDescriptionLevelFull) {
550061da546Spatrick       s->IndentLess();
551061da546Spatrick       s->IndentMore();
552061da546Spatrick     }
553061da546Spatrick   }
554061da546Spatrick 
555061da546Spatrick   if (m_callback_baton_sp.get()) {
556061da546Spatrick     if (level != eDescriptionLevelBrief) {
557061da546Spatrick       s->EOL();
558061da546Spatrick       m_callback_baton_sp->GetDescription(s->AsRawOstream(), level,
559061da546Spatrick                                           s->GetIndentLevel());
560061da546Spatrick     }
561061da546Spatrick   }
562061da546Spatrick   if (!m_condition_text.empty()) {
563061da546Spatrick     if (level != eDescriptionLevelBrief) {
564061da546Spatrick       s->EOL();
565061da546Spatrick       s->Printf("Condition: %s\n", m_condition_text.c_str());
566061da546Spatrick     }
567061da546Spatrick   }
568061da546Spatrick }
569061da546Spatrick 
GetDescription(llvm::raw_ostream & s,lldb::DescriptionLevel level,unsigned indentation) const570061da546Spatrick void BreakpointOptions::CommandBaton::GetDescription(
571061da546Spatrick     llvm::raw_ostream &s, lldb::DescriptionLevel level,
572061da546Spatrick     unsigned indentation) const {
573061da546Spatrick   const CommandData *data = getItem();
574061da546Spatrick 
575061da546Spatrick   if (level == eDescriptionLevelBrief) {
576061da546Spatrick     s << ", commands = "
577061da546Spatrick       << ((data && data->user_source.GetSize() > 0) ? "yes" : "no");
578061da546Spatrick     return;
579061da546Spatrick   }
580061da546Spatrick 
581061da546Spatrick   indentation += 2;
582061da546Spatrick   s.indent(indentation);
583061da546Spatrick   s << "Breakpoint commands";
584061da546Spatrick   if (data->interpreter != eScriptLanguageNone)
585061da546Spatrick     s << llvm::formatv(" ({0}):\n",
586061da546Spatrick                        ScriptInterpreter::LanguageToString(data->interpreter));
587061da546Spatrick   else
588061da546Spatrick     s << ":\n";
589061da546Spatrick 
590061da546Spatrick   indentation += 2;
591061da546Spatrick   if (data && data->user_source.GetSize() > 0) {
592061da546Spatrick     for (llvm::StringRef str : data->user_source) {
593061da546Spatrick       s.indent(indentation);
594061da546Spatrick       s << str << "\n";
595061da546Spatrick     }
596061da546Spatrick   } else
597061da546Spatrick     s << "No commands.\n";
598061da546Spatrick }
599061da546Spatrick 
SetCommandDataCallback(std::unique_ptr<CommandData> & cmd_data)600061da546Spatrick void BreakpointOptions::SetCommandDataCallback(
601061da546Spatrick     std::unique_ptr<CommandData> &cmd_data) {
602061da546Spatrick   cmd_data->interpreter = eScriptLanguageNone;
603061da546Spatrick   auto baton_sp = std::make_shared<CommandBaton>(std::move(cmd_data));
604061da546Spatrick   SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, baton_sp);
605061da546Spatrick   m_set_flags.Set(eCallback);
606061da546Spatrick }
607061da546Spatrick 
BreakpointOptionsCallbackFunction(void * baton,StoppointCallbackContext * context,lldb::user_id_t break_id,lldb::user_id_t break_loc_id)608061da546Spatrick bool BreakpointOptions::BreakpointOptionsCallbackFunction(
609061da546Spatrick     void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
610061da546Spatrick     lldb::user_id_t break_loc_id) {
611061da546Spatrick   bool ret_value = true;
612061da546Spatrick   if (baton == nullptr)
613061da546Spatrick     return true;
614061da546Spatrick 
615061da546Spatrick   CommandData *data = (CommandData *)baton;
616061da546Spatrick   StringList &commands = data->user_source;
617061da546Spatrick 
618061da546Spatrick   if (commands.GetSize() > 0) {
619061da546Spatrick     ExecutionContext exe_ctx(context->exe_ctx_ref);
620061da546Spatrick     Target *target = exe_ctx.GetTargetPtr();
621061da546Spatrick     if (target) {
622061da546Spatrick       Debugger &debugger = target->GetDebugger();
623dda28197Spatrick       CommandReturnObject result(debugger.GetUseColor());
624dda28197Spatrick 
625061da546Spatrick       // Rig up the results secondary output stream to the debugger's, so the
626061da546Spatrick       // output will come out synchronously if the debugger is set up that way.
627061da546Spatrick       StreamSP output_stream(debugger.GetAsyncOutputStream());
628061da546Spatrick       StreamSP error_stream(debugger.GetAsyncErrorStream());
629061da546Spatrick       result.SetImmediateOutputStream(output_stream);
630061da546Spatrick       result.SetImmediateErrorStream(error_stream);
631061da546Spatrick 
632061da546Spatrick       CommandInterpreterRunOptions options;
633061da546Spatrick       options.SetStopOnContinue(true);
634061da546Spatrick       options.SetStopOnError(data->stop_on_error);
635061da546Spatrick       options.SetEchoCommands(true);
636061da546Spatrick       options.SetPrintResults(true);
637061da546Spatrick       options.SetPrintErrors(true);
638061da546Spatrick       options.SetAddToHistory(false);
639061da546Spatrick 
640be691f3bSpatrick       debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx,
641061da546Spatrick                                                       options, result);
642061da546Spatrick       result.GetImmediateOutputStream()->Flush();
643061da546Spatrick       result.GetImmediateErrorStream()->Flush();
644061da546Spatrick     }
645061da546Spatrick   }
646061da546Spatrick   return ret_value;
647061da546Spatrick }
648061da546Spatrick 
Clear()649061da546Spatrick void BreakpointOptions::Clear()
650061da546Spatrick {
651061da546Spatrick   m_set_flags.Clear();
652061da546Spatrick   m_thread_spec_up.release();
653061da546Spatrick   m_one_shot = false;
654061da546Spatrick   m_ignore_count = 0;
655061da546Spatrick   m_auto_continue = false;
656061da546Spatrick   m_callback = nullptr;
657061da546Spatrick   m_callback_baton_sp.reset();
658061da546Spatrick   m_baton_is_command_baton = false;
659061da546Spatrick   m_callback_is_synchronous = false;
660061da546Spatrick   m_enabled = false;
661061da546Spatrick   m_condition_text.clear();
662061da546Spatrick }
663