180814287SRaphael Isemann //===-- BreakpointOptions.cpp ---------------------------------------------===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner 
916fd7511SEugene Zelenko #include "lldb/Breakpoint/BreakpointOptions.h"
1016fd7511SEugene Zelenko 
11b9c1b51eSKate Stone #include "lldb/Breakpoint/StoppointCallbackContext.h"
1236f3b369SJim Ingham #include "lldb/Core/Value.h"
13e14dc268SJim Ingham #include "lldb/Interpreter/CommandInterpreter.h"
14e14dc268SJim Ingham #include "lldb/Interpreter/CommandReturnObject.h"
1536f3b369SJim Ingham #include "lldb/Target/Process.h"
16f7c3e27fSSean Callanan #include "lldb/Target/Target.h"
171b54c88cSJim Ingham #include "lldb/Target/ThreadSpec.h"
18bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
19573ab909SZachary Turner #include "lldb/Utility/StringList.h"
2030fdc8d8SChris Lattner 
214e4fbe82SZachary Turner #include "llvm/ADT/STLExtras.h"
224e4fbe82SZachary Turner 
2330fdc8d8SChris Lattner using namespace lldb;
2430fdc8d8SChris Lattner using namespace lldb_private;
2530fdc8d8SChris Lattner 
2675f0f583SJim Ingham const char
2775f0f583SJim Ingham     *BreakpointOptions::CommandData::g_option_names[static_cast<uint32_t>(
2875f0f583SJim Ingham         BreakpointOptions::CommandData::OptionNames::LastOptionName)]{
29e14dc268SJim Ingham         "UserSource", "ScriptSource", "StopOnError"};
30e14dc268SJim Ingham 
31e14dc268SJim Ingham StructuredData::ObjectSP
SerializeToStructuredData()32e14dc268SJim Ingham BreakpointOptions::CommandData::SerializeToStructuredData() {
33e14dc268SJim Ingham   size_t num_strings = user_source.GetSize();
34e14dc268SJim Ingham   if (num_strings == 0 && script_source.empty()) {
35e14dc268SJim Ingham     // We shouldn't serialize commands if there aren't any, return an empty sp
36e14dc268SJim Ingham     // to indicate this.
37e14dc268SJim Ingham     return StructuredData::ObjectSP();
38e14dc268SJim Ingham   }
39e14dc268SJim Ingham 
40e14dc268SJim Ingham   StructuredData::DictionarySP options_dict_sp(
41e14dc268SJim Ingham       new StructuredData::Dictionary());
42e14dc268SJim Ingham   options_dict_sp->AddBooleanItem(GetKey(OptionNames::StopOnError),
43e14dc268SJim Ingham                                   stop_on_error);
44e14dc268SJim Ingham 
45e14dc268SJim Ingham   StructuredData::ArraySP user_source_sp(new StructuredData::Array());
46e14dc268SJim Ingham   for (size_t i = 0; i < num_strings; i++) {
47e14dc268SJim Ingham     StructuredData::StringSP item_sp(
48e14dc268SJim Ingham         new StructuredData::String(user_source[i]));
49e14dc268SJim Ingham     user_source_sp->AddItem(item_sp);
50e14dc268SJim Ingham     options_dict_sp->AddItem(GetKey(OptionNames::UserSource), user_source_sp);
51e14dc268SJim Ingham   }
52e14dc268SJim Ingham 
53f7e07256SJim Ingham   options_dict_sp->AddStringItem(
54f7e07256SJim Ingham       GetKey(OptionNames::Interpreter),
55f7e07256SJim Ingham       ScriptInterpreter::LanguageToString(interpreter));
56e14dc268SJim Ingham   return options_dict_sp;
57e14dc268SJim Ingham }
58e14dc268SJim Ingham 
591a81b273SJim Ingham std::unique_ptr<BreakpointOptions::CommandData>
CreateFromStructuredData(const StructuredData::Dictionary & options_dict,Status & error)60e14dc268SJim Ingham BreakpointOptions::CommandData::CreateFromStructuredData(
6197206d57SZachary Turner     const StructuredData::Dictionary &options_dict, Status &error) {
6292d1960eSJim Ingham   std::unique_ptr<CommandData> data_up(new CommandData());
6392d1960eSJim Ingham 
64e14dc268SJim Ingham   bool success = options_dict.GetValueForKeyAsBoolean(
6592d1960eSJim Ingham       GetKey(OptionNames::StopOnError), data_up->stop_on_error);
6692d1960eSJim Ingham 
672833321fSZachary Turner   llvm::StringRef interpreter_str;
68f7e07256SJim Ingham   ScriptLanguage interp_language;
69e14dc268SJim Ingham   success = options_dict.GetValueForKeyAsString(
70f7e07256SJim Ingham       GetKey(OptionNames::Interpreter), interpreter_str);
7192d1960eSJim Ingham 
72f7e07256SJim Ingham   if (!success) {
73f7e07256SJim Ingham     error.SetErrorString("Missing command language value.");
74f7e07256SJim Ingham     return data_up;
75f7e07256SJim Ingham   }
76f7e07256SJim Ingham 
77f7e07256SJim Ingham   interp_language = ScriptInterpreter::StringToLanguage(interpreter_str);
78f7e07256SJim Ingham   if (interp_language == eScriptLanguageUnknown) {
79827d5d74SZachary Turner     error.SetErrorStringWithFormatv("Unknown breakpoint command language: {0}.",
80827d5d74SZachary Turner                                     interpreter_str);
81f7e07256SJim Ingham     return data_up;
82f7e07256SJim Ingham   }
83f7e07256SJim Ingham   data_up->interpreter = interp_language;
84e14dc268SJim Ingham 
85e14dc268SJim Ingham   StructuredData::Array *user_source;
86e14dc268SJim Ingham   success = options_dict.GetValueForKeyAsArray(GetKey(OptionNames::UserSource),
87e14dc268SJim Ingham                                                user_source);
88e14dc268SJim Ingham   if (success) {
89e14dc268SJim Ingham     size_t num_elems = user_source->GetSize();
90e14dc268SJim Ingham     for (size_t i = 0; i < num_elems; i++) {
912833321fSZachary Turner       llvm::StringRef elem_string;
92e14dc268SJim Ingham       success = user_source->GetItemAtIndexAsString(i, elem_string);
93e14dc268SJim Ingham       if (success)
9492d1960eSJim Ingham         data_up->user_source.AppendString(elem_string);
95e14dc268SJim Ingham     }
96e14dc268SJim Ingham   }
9792d1960eSJim Ingham 
9892d1960eSJim Ingham   return data_up;
99e14dc268SJim Ingham }
100e14dc268SJim Ingham 
101778ef392SJim Ingham const char *BreakpointOptions::g_option_names[(
102778ef392SJim Ingham     size_t)BreakpointOptions::OptionNames::LastOptionName]{
103f08f5c99SJim Ingham     "ConditionText", "IgnoreCount",
104f08f5c99SJim Ingham     "EnabledState", "OneShotState", "AutoContinue"};
105e14dc268SJim Ingham 
NullCallback(void * baton,StoppointCallbackContext * context,lldb::user_id_t break_id,lldb::user_id_t break_loc_id)106b9c1b51eSKate Stone bool BreakpointOptions::NullCallback(void *baton,
107b9c1b51eSKate Stone                                      StoppointCallbackContext *context,
108b9c1b51eSKate Stone                                      lldb::user_id_t break_id,
109b9c1b51eSKate Stone                                      lldb::user_id_t break_loc_id) {
11030fdc8d8SChris Lattner   return true;
11130fdc8d8SChris Lattner }
11230fdc8d8SChris Lattner 
11330fdc8d8SChris Lattner // BreakpointOptions constructor
BreakpointOptions(bool all_flags_set)114af26b22cSJim Ingham BreakpointOptions::BreakpointOptions(bool all_flags_set)
115*ee4b6cf5SKazu Hirata     : m_callback(BreakpointOptions::NullCallback),
116e14dc268SJim Ingham       m_baton_is_command_baton(false), m_callback_is_synchronous(false),
117*ee4b6cf5SKazu Hirata       m_enabled(true), m_one_shot(false), m_ignore_count(0),
118*ee4b6cf5SKazu Hirata       m_condition_text_hash(0), m_auto_continue(false), m_set_flags(0) {
119af26b22cSJim Ingham   if (all_flags_set)
120af26b22cSJim Ingham     m_set_flags.Set(~((Flags::ValueType)0));
121af26b22cSJim Ingham }
122e14dc268SJim Ingham 
BreakpointOptions(const char * condition,bool enabled,int32_t ignore,bool one_shot,bool auto_continue)123e14dc268SJim Ingham BreakpointOptions::BreakpointOptions(const char *condition, bool enabled,
124f08f5c99SJim Ingham                                      int32_t ignore, bool one_shot,
125f08f5c99SJim Ingham                                      bool auto_continue)
126e14dc268SJim Ingham     : m_callback(nullptr), m_baton_is_command_baton(false),
127e14dc268SJim Ingham       m_callback_is_synchronous(false), m_enabled(enabled),
128b842f2ecSJim Ingham       m_one_shot(one_shot), m_ignore_count(ignore),
129f08f5c99SJim Ingham       m_condition_text_hash(0), m_auto_continue(auto_continue)
130af26b22cSJim Ingham {
131f08f5c99SJim Ingham     m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot
132b842f2ecSJim Ingham                    | eAutoContinue);
133b842f2ecSJim Ingham     if (condition && *condition != '\0') {
134b842f2ecSJim Ingham       SetCondition(condition);
135b842f2ecSJim Ingham     }
136af26b22cSJim Ingham }
13730fdc8d8SChris Lattner 
13830fdc8d8SChris Lattner // BreakpointOptions copy constructor
BreakpointOptions(const BreakpointOptions & rhs)139b9c1b51eSKate Stone BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs)
140b9c1b51eSKate Stone     : m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp),
141e14dc268SJim Ingham       m_baton_is_command_baton(rhs.m_baton_is_command_baton),
14230fdc8d8SChris Lattner       m_callback_is_synchronous(rhs.m_callback_is_synchronous),
143b9c1b51eSKate Stone       m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot),
144*ee4b6cf5SKazu Hirata       m_ignore_count(rhs.m_ignore_count), m_auto_continue(rhs.m_auto_continue),
145*ee4b6cf5SKazu Hirata       m_set_flags(rhs.m_set_flags) {
146d5b44036SJonas Devlieghere   if (rhs.m_thread_spec_up != nullptr)
14706412daeSJonas Devlieghere     m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
1483dbf346eSSean Callanan   m_condition_text = rhs.m_condition_text;
1493dbf346eSSean Callanan   m_condition_text_hash = rhs.m_condition_text_hash;
15030fdc8d8SChris Lattner }
15130fdc8d8SChris Lattner 
15230fdc8d8SChris Lattner // BreakpointOptions assignment operator
153b9c1b51eSKate Stone const BreakpointOptions &BreakpointOptions::
operator =(const BreakpointOptions & rhs)154b9c1b51eSKate Stone operator=(const BreakpointOptions &rhs) {
15530fdc8d8SChris Lattner   m_callback = rhs.m_callback;
15630fdc8d8SChris Lattner   m_callback_baton_sp = rhs.m_callback_baton_sp;
157e14dc268SJim Ingham   m_baton_is_command_baton = rhs.m_baton_is_command_baton;
15830fdc8d8SChris Lattner   m_callback_is_synchronous = rhs.m_callback_is_synchronous;
15930fdc8d8SChris Lattner   m_enabled = rhs.m_enabled;
160ca36cd16SJim Ingham   m_one_shot = rhs.m_one_shot;
16130fdc8d8SChris Lattner   m_ignore_count = rhs.m_ignore_count;
162d5b44036SJonas Devlieghere   if (rhs.m_thread_spec_up != nullptr)
16306412daeSJonas Devlieghere     m_thread_spec_up = std::make_unique<ThreadSpec>(*rhs.m_thread_spec_up);
1643dbf346eSSean Callanan   m_condition_text = rhs.m_condition_text;
1653dbf346eSSean Callanan   m_condition_text_hash = rhs.m_condition_text_hash;
166f08f5c99SJim Ingham   m_auto_continue = rhs.m_auto_continue;
167af26b22cSJim Ingham   m_set_flags = rhs.m_set_flags;
16830fdc8d8SChris Lattner   return *this;
16930fdc8d8SChris Lattner }
17030fdc8d8SChris Lattner 
CopyOverSetOptions(const BreakpointOptions & incoming)171b842f2ecSJim Ingham void BreakpointOptions::CopyOverSetOptions(const BreakpointOptions &incoming)
172b842f2ecSJim Ingham {
173b842f2ecSJim Ingham   if (incoming.m_set_flags.Test(eEnabled))
174b842f2ecSJim Ingham   {
175b842f2ecSJim Ingham     m_enabled = incoming.m_enabled;
176b842f2ecSJim Ingham     m_set_flags.Set(eEnabled);
177b842f2ecSJim Ingham   }
178b842f2ecSJim Ingham   if (incoming.m_set_flags.Test(eOneShot))
179b842f2ecSJim Ingham   {
180b842f2ecSJim Ingham     m_one_shot = incoming.m_one_shot;
181b842f2ecSJim Ingham     m_set_flags.Set(eOneShot);
182b842f2ecSJim Ingham   }
183b842f2ecSJim Ingham   if (incoming.m_set_flags.Test(eCallback))
184b842f2ecSJim Ingham   {
185b842f2ecSJim Ingham     m_callback = incoming.m_callback;
186b842f2ecSJim Ingham     m_callback_baton_sp = incoming.m_callback_baton_sp;
187b842f2ecSJim Ingham     m_callback_is_synchronous = incoming.m_callback_is_synchronous;
188b842f2ecSJim Ingham     m_baton_is_command_baton = incoming.m_baton_is_command_baton;
189b842f2ecSJim Ingham     m_set_flags.Set(eCallback);
190b842f2ecSJim Ingham   }
191b842f2ecSJim Ingham   if (incoming.m_set_flags.Test(eIgnoreCount))
192b842f2ecSJim Ingham   {
193b842f2ecSJim Ingham     m_ignore_count = incoming.m_ignore_count;
194b842f2ecSJim Ingham     m_set_flags.Set(eIgnoreCount);
195b842f2ecSJim Ingham   }
196b842f2ecSJim Ingham   if (incoming.m_set_flags.Test(eCondition))
197b842f2ecSJim Ingham   {
198b842f2ecSJim Ingham     // If we're copying over an empty condition, mark it as unset.
199b842f2ecSJim Ingham     if (incoming.m_condition_text.empty()) {
200b842f2ecSJim Ingham       m_condition_text.clear();
201b842f2ecSJim Ingham       m_condition_text_hash = 0;
202b842f2ecSJim Ingham       m_set_flags.Clear(eCondition);
203b842f2ecSJim Ingham     } else {
204b842f2ecSJim Ingham       m_condition_text = incoming.m_condition_text;
205b842f2ecSJim Ingham       m_condition_text_hash = incoming.m_condition_text_hash;
206b842f2ecSJim Ingham       m_set_flags.Set(eCondition);
207b842f2ecSJim Ingham     }
208b842f2ecSJim Ingham   }
209b842f2ecSJim Ingham   if (incoming.m_set_flags.Test(eAutoContinue))
210b842f2ecSJim Ingham   {
211b842f2ecSJim Ingham     m_auto_continue = incoming.m_auto_continue;
212b842f2ecSJim Ingham     m_set_flags.Set(eAutoContinue);
213b842f2ecSJim Ingham   }
214d5b44036SJonas Devlieghere   if (incoming.m_set_flags.Test(eThreadSpec) && incoming.m_thread_spec_up) {
215d5b44036SJonas Devlieghere     if (!m_thread_spec_up)
21606412daeSJonas Devlieghere       m_thread_spec_up =
21706412daeSJonas Devlieghere           std::make_unique<ThreadSpec>(*incoming.m_thread_spec_up);
218b842f2ecSJim Ingham     else
219d5b44036SJonas Devlieghere       *m_thread_spec_up = *incoming.m_thread_spec_up;
220b842f2ecSJim Ingham     m_set_flags.Set(eThreadSpec);
221b842f2ecSJim Ingham   }
222b842f2ecSJim Ingham }
223b842f2ecSJim Ingham 
22430fdc8d8SChris Lattner // Destructor
22516fd7511SEugene Zelenko BreakpointOptions::~BreakpointOptions() = default;
22630fdc8d8SChris Lattner 
CreateFromStructuredData(Target & target,const StructuredData::Dictionary & options_dict,Status & error)2271a81b273SJim Ingham std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData(
228f7e07256SJim Ingham     Target &target, const StructuredData::Dictionary &options_dict,
22997206d57SZachary Turner     Status &error) {
230e14dc268SJim Ingham   bool enabled = true;
231e14dc268SJim Ingham   bool one_shot = false;
232f08f5c99SJim Ingham   bool auto_continue = false;
233e14dc268SJim Ingham   int32_t ignore_count = 0;
234af26b22cSJim Ingham   llvm::StringRef condition_ref("");
235af26b22cSJim Ingham   Flags set_options;
236e14dc268SJim Ingham 
237af26b22cSJim Ingham   const char *key = GetKey(OptionNames::EnabledState);
238af26b22cSJim Ingham   bool success;
239bac29fdeSJim Ingham   if (key && options_dict.HasKey(key)) {
240af26b22cSJim Ingham     success = options_dict.GetValueForKeyAsBoolean(key, enabled);
241e14dc268SJim Ingham     if (!success) {
242bac29fdeSJim Ingham       error.SetErrorStringWithFormat("%s key is not a boolean.", key);
243e14dc268SJim Ingham       return nullptr;
244e14dc268SJim Ingham     }
245af26b22cSJim Ingham     set_options.Set(eEnabled);
246af26b22cSJim Ingham   }
247e14dc268SJim Ingham 
248af26b22cSJim Ingham   key = GetKey(OptionNames::OneShotState);
249bac29fdeSJim Ingham   if (key && options_dict.HasKey(key)) {
250af26b22cSJim Ingham     success = options_dict.GetValueForKeyAsBoolean(key, one_shot);
251e14dc268SJim Ingham     if (!success) {
252bac29fdeSJim Ingham       error.SetErrorStringWithFormat("%s key is not a boolean.", key);
253e14dc268SJim Ingham       return nullptr;
254e14dc268SJim Ingham       }
255af26b22cSJim Ingham       set_options.Set(eOneShot);
256af26b22cSJim Ingham   }
257af26b22cSJim Ingham 
258f08f5c99SJim Ingham   key = GetKey(OptionNames::AutoContinue);
259bac29fdeSJim Ingham   if (key && options_dict.HasKey(key)) {
260f08f5c99SJim Ingham     success = options_dict.GetValueForKeyAsBoolean(key, auto_continue);
261f08f5c99SJim Ingham     if (!success) {
262bac29fdeSJim Ingham       error.SetErrorStringWithFormat("%s key is not a boolean.", key);
263f08f5c99SJim Ingham       return nullptr;
264f08f5c99SJim Ingham       }
265f08f5c99SJim Ingham       set_options.Set(eAutoContinue);
266f08f5c99SJim Ingham   }
267f08f5c99SJim Ingham 
268af26b22cSJim Ingham   key = GetKey(OptionNames::IgnoreCount);
269bac29fdeSJim Ingham   if (key && options_dict.HasKey(key)) {
270af26b22cSJim Ingham     success = options_dict.GetValueForKeyAsInteger(key, ignore_count);
271e14dc268SJim Ingham     if (!success) {
272bac29fdeSJim Ingham       error.SetErrorStringWithFormat("%s key is not an integer.", key);
273e14dc268SJim Ingham       return nullptr;
274e14dc268SJim Ingham     }
275af26b22cSJim Ingham     set_options.Set(eIgnoreCount);
276af26b22cSJim Ingham   }
277af26b22cSJim Ingham 
278af26b22cSJim Ingham   key = GetKey(OptionNames::ConditionText);
279bac29fdeSJim Ingham   if (key && options_dict.HasKey(key)) {
280af26b22cSJim Ingham     success = options_dict.GetValueForKeyAsString(key, condition_ref);
281af26b22cSJim Ingham     if (!success) {
282bac29fdeSJim Ingham       error.SetErrorStringWithFormat("%s key is not an string.", key);
283af26b22cSJim Ingham       return nullptr;
284af26b22cSJim Ingham     }
285af26b22cSJim Ingham     set_options.Set(eCondition);
286af26b22cSJim Ingham   }
287e14dc268SJim Ingham 
28892d1960eSJim Ingham   std::unique_ptr<CommandData> cmd_data_up;
289e14dc268SJim Ingham   StructuredData::Dictionary *cmds_dict;
290e14dc268SJim Ingham   success = options_dict.GetValueForKeyAsDictionary(
291e14dc268SJim Ingham       CommandData::GetSerializationKey(), cmds_dict);
292e14dc268SJim Ingham   if (success && cmds_dict) {
29397206d57SZachary Turner     Status cmds_error;
29492d1960eSJim Ingham     cmd_data_up = CommandData::CreateFromStructuredData(*cmds_dict, cmds_error);
295e14dc268SJim Ingham     if (cmds_error.Fail()) {
296e14dc268SJim Ingham       error.SetErrorStringWithFormat(
297e14dc268SJim Ingham           "Failed to deserialize breakpoint command options: %s.",
298e14dc268SJim Ingham           cmds_error.AsCString());
299e14dc268SJim Ingham       return nullptr;
300e14dc268SJim Ingham     }
301e14dc268SJim Ingham   }
302e14dc268SJim Ingham 
303a8f3ae7cSJonas Devlieghere   auto bp_options = std::make_unique<BreakpointOptions>(
304f08f5c99SJim Ingham       condition_ref.str().c_str(), enabled,
305f08f5c99SJim Ingham       ignore_count, one_shot, auto_continue);
30670355aceSJonas Devlieghere   if (cmd_data_up) {
307f7e07256SJim Ingham     if (cmd_data_up->interpreter == eScriptLanguageNone)
30892d1960eSJim Ingham       bp_options->SetCommandDataCallback(cmd_data_up);
309f7e07256SJim Ingham     else {
3102b29b432SJonas Devlieghere       ScriptInterpreter *interp = target.GetDebugger().GetScriptInterpreter();
311f7e07256SJim Ingham       if (!interp) {
31289533764SJonas Devlieghere         error.SetErrorString(
313f7e07256SJim Ingham             "Can't set script commands - no script interpreter");
314f7e07256SJim Ingham         return nullptr;
315f7e07256SJim Ingham       }
316f7e07256SJim Ingham       if (interp->GetLanguage() != cmd_data_up->interpreter) {
317f7e07256SJim Ingham         error.SetErrorStringWithFormat(
318f7e07256SJim Ingham             "Current script language doesn't match breakpoint's language: %s",
319f7e07256SJim Ingham             ScriptInterpreter::LanguageToString(cmd_data_up->interpreter)
320f7e07256SJim Ingham                 .c_str());
321f7e07256SJim Ingham         return nullptr;
322f7e07256SJim Ingham       }
32397206d57SZachary Turner       Status script_error;
324f7e07256SJim Ingham       script_error =
325cfb96d84SJim Ingham           interp->SetBreakpointCommandCallback(*bp_options, cmd_data_up);
326f7e07256SJim Ingham       if (script_error.Fail()) {
327f7e07256SJim Ingham         error.SetErrorStringWithFormat("Error generating script callback: %s.",
328f7e07256SJim Ingham                                        error.AsCString());
329f7e07256SJim Ingham         return nullptr;
330f7e07256SJim Ingham       }
331f7e07256SJim Ingham     }
332f7e07256SJim Ingham   }
333778ef392SJim Ingham 
334778ef392SJim Ingham   StructuredData::Dictionary *thread_spec_dict;
335778ef392SJim Ingham   success = options_dict.GetValueForKeyAsDictionary(
336778ef392SJim Ingham       ThreadSpec::GetSerializationKey(), thread_spec_dict);
337778ef392SJim Ingham   if (success) {
33897206d57SZachary Turner     Status thread_spec_error;
339778ef392SJim Ingham     std::unique_ptr<ThreadSpec> thread_spec_up =
340778ef392SJim Ingham         ThreadSpec::CreateFromStructuredData(*thread_spec_dict,
341778ef392SJim Ingham                                              thread_spec_error);
342778ef392SJim Ingham     if (thread_spec_error.Fail()) {
343778ef392SJim Ingham       error.SetErrorStringWithFormat(
344778ef392SJim Ingham           "Failed to deserialize breakpoint thread spec options: %s.",
345778ef392SJim Ingham           thread_spec_error.AsCString());
346778ef392SJim Ingham       return nullptr;
347778ef392SJim Ingham     }
348778ef392SJim Ingham     bp_options->SetThreadSpec(thread_spec_up);
349778ef392SJim Ingham   }
3504e4fbe82SZachary Turner   return bp_options;
351e14dc268SJim Ingham }
352e14dc268SJim Ingham 
SerializeToStructuredData()353e14dc268SJim Ingham StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() {
354e14dc268SJim Ingham   StructuredData::DictionarySP options_dict_sp(
355e14dc268SJim Ingham       new StructuredData::Dictionary());
356b842f2ecSJim Ingham   if (m_set_flags.Test(eEnabled))
357af26b22cSJim Ingham     options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState),
358af26b22cSJim Ingham                                     m_enabled);
359b842f2ecSJim Ingham   if (m_set_flags.Test(eOneShot))
360e14dc268SJim Ingham     options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState),
361e14dc268SJim Ingham                                m_one_shot);
362b842f2ecSJim Ingham   if (m_set_flags.Test(eAutoContinue))
363f08f5c99SJim Ingham     options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue),
364f08f5c99SJim Ingham                                m_auto_continue);
365b842f2ecSJim Ingham   if (m_set_flags.Test(eIgnoreCount))
366e14dc268SJim Ingham     options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount),
367e14dc268SJim Ingham                                     m_ignore_count);
368b842f2ecSJim Ingham   if (m_set_flags.Test(eCondition))
369e14dc268SJim Ingham     options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText),
370e14dc268SJim Ingham                                    m_condition_text);
371af26b22cSJim Ingham 
372b842f2ecSJim Ingham   if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) {
3734e4fbe82SZachary Turner     auto cmd_baton =
3744e4fbe82SZachary Turner         std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
375e14dc268SJim Ingham     StructuredData::ObjectSP commands_sp =
3764e4fbe82SZachary Turner         cmd_baton->getItem()->SerializeToStructuredData();
377e14dc268SJim Ingham     if (commands_sp) {
378e14dc268SJim Ingham       options_dict_sp->AddItem(
379e14dc268SJim Ingham           BreakpointOptions::CommandData::GetSerializationKey(), commands_sp);
380e14dc268SJim Ingham     }
381e14dc268SJim Ingham   }
382d5b44036SJonas Devlieghere   if (m_set_flags.Test(eThreadSpec) && m_thread_spec_up) {
383778ef392SJim Ingham     StructuredData::ObjectSP thread_spec_sp =
384d5b44036SJonas Devlieghere         m_thread_spec_up->SerializeToStructuredData();
385778ef392SJim Ingham     options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), thread_spec_sp);
386778ef392SJim Ingham   }
387778ef392SJim Ingham 
388e14dc268SJim Ingham   return options_dict_sp;
389e14dc268SJim Ingham }
390e14dc268SJim Ingham 
39130fdc8d8SChris Lattner // Callbacks
SetCallback(BreakpointHitCallback callback,const lldb::BatonSP & callback_baton_sp,bool callback_is_synchronous)392b9c1b51eSKate Stone void BreakpointOptions::SetCallback(BreakpointHitCallback callback,
393e14dc268SJim Ingham                                     const lldb::BatonSP &callback_baton_sp,
394b9c1b51eSKate Stone                                     bool callback_is_synchronous) {
3954e4fbe82SZachary Turner   // FIXME: This seems unsafe.  If BatonSP actually *is* a CommandBaton, but
39605097246SAdrian Prantl   // in a shared_ptr<Baton> instead of a shared_ptr<CommandBaton>, then we will
39705097246SAdrian Prantl   // set m_baton_is_command_baton to false, which is incorrect. One possible
39805097246SAdrian Prantl   // solution is to make the base Baton class provide a method such as:
3994e4fbe82SZachary Turner   //     virtual StringRef getBatonId() const { return ""; }
4004e4fbe82SZachary Turner   // and have CommandBaton override this to return something unique, and then
4014e4fbe82SZachary Turner   // check for it here.  Another option might be to make Baton using the llvm
4024e4fbe82SZachary Turner   // casting infrastructure, so that we could write something like:
4034e4fbe82SZachary Turner   //     if (llvm::isa<CommandBaton>(callback_baton_sp))
4044e4fbe82SZachary Turner   // at relevant callsites instead of storing a boolean.
40530fdc8d8SChris Lattner   m_callback_is_synchronous = callback_is_synchronous;
40630fdc8d8SChris Lattner   m_callback = callback;
40730fdc8d8SChris Lattner   m_callback_baton_sp = callback_baton_sp;
408e14dc268SJim Ingham   m_baton_is_command_baton = false;
409af26b22cSJim Ingham   m_set_flags.Set(eCallback);
410e14dc268SJim Ingham }
411e14dc268SJim Ingham 
SetCallback(BreakpointHitCallback callback,const BreakpointOptions::CommandBatonSP & callback_baton_sp,bool callback_is_synchronous)412e14dc268SJim Ingham void BreakpointOptions::SetCallback(
413e14dc268SJim Ingham     BreakpointHitCallback callback,
414e14dc268SJim Ingham     const BreakpointOptions::CommandBatonSP &callback_baton_sp,
415e14dc268SJim Ingham     bool callback_is_synchronous) {
416e14dc268SJim Ingham   m_callback_is_synchronous = callback_is_synchronous;
417e14dc268SJim Ingham   m_callback = callback;
418e14dc268SJim Ingham   m_callback_baton_sp = callback_baton_sp;
419e14dc268SJim Ingham   m_baton_is_command_baton = true;
420af26b22cSJim Ingham   m_set_flags.Set(eCallback);
42130fdc8d8SChris Lattner }
42230fdc8d8SChris Lattner 
ClearCallback()423b9c1b51eSKate Stone void BreakpointOptions::ClearCallback() {
42436f3b369SJim Ingham   m_callback = BreakpointOptions::NullCallback;
42536f3b369SJim Ingham   m_callback_is_synchronous = false;
42630fdc8d8SChris Lattner   m_callback_baton_sp.reset();
427e14dc268SJim Ingham   m_baton_is_command_baton = false;
428af26b22cSJim Ingham   m_set_flags.Clear(eCallback);
42930fdc8d8SChris Lattner }
43030fdc8d8SChris Lattner 
GetBaton()431b9c1b51eSKate Stone Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); }
432b9c1b51eSKate Stone 
GetBaton() const433b9c1b51eSKate Stone const Baton *BreakpointOptions::GetBaton() const {
43430fdc8d8SChris Lattner   return m_callback_baton_sp.get();
43530fdc8d8SChris Lattner }
43630fdc8d8SChris Lattner 
InvokeCallback(StoppointCallbackContext * context,lldb::user_id_t break_id,lldb::user_id_t break_loc_id)437b9c1b51eSKate Stone bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context,
43830fdc8d8SChris Lattner                                        lldb::user_id_t break_id,
439b9c1b51eSKate Stone                                        lldb::user_id_t break_loc_id) {
440e8b072d9SJim Ingham   if (m_callback) {
441e8b072d9SJim Ingham     if (context->is_synchronous == IsCallbackSynchronous()) {
4424e4fbe82SZachary Turner         return m_callback(m_callback_baton_sp ? m_callback_baton_sp->data()
443b9c1b51eSKate Stone                                           : nullptr,
444b9c1b51eSKate Stone                       context, break_id, break_loc_id);
445e8b072d9SJim Ingham     } else if (IsCallbackSynchronous()) {
4469d081a7fSJim Ingham       return false;
447e8b072d9SJim Ingham     }
448e8b072d9SJim Ingham   }
44930fdc8d8SChris Lattner   return true;
45030fdc8d8SChris Lattner }
45130fdc8d8SChris Lattner 
HasCallback() const452b9c1b51eSKate Stone bool BreakpointOptions::HasCallback() const {
4530136309fSJim Ingham   return m_callback != BreakpointOptions::NullCallback;
4540136309fSJim Ingham }
4550136309fSJim Ingham 
GetCommandLineCallbacks(StringList & command_list)45692d1960eSJim Ingham bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) {
45792d1960eSJim Ingham   if (!HasCallback())
45892d1960eSJim Ingham     return false;
45992d1960eSJim Ingham   if (!m_baton_is_command_baton)
46092d1960eSJim Ingham     return false;
46192d1960eSJim Ingham 
46292d1960eSJim Ingham   auto cmd_baton = std::static_pointer_cast<CommandBaton>(m_callback_baton_sp);
46392d1960eSJim Ingham   CommandData *data = cmd_baton->getItem();
46492d1960eSJim Ingham   if (!data)
46592d1960eSJim Ingham     return false;
46692d1960eSJim Ingham   command_list = data->user_source;
46792d1960eSJim Ingham   return true;
46892d1960eSJim Ingham }
46992d1960eSJim Ingham 
SetCondition(const char * condition)470b9c1b51eSKate Stone void BreakpointOptions::SetCondition(const char *condition) {
471af26b22cSJim Ingham   if (!condition || condition[0] == '\0') {
472ec537a24SSean Callanan     condition = "";
473af26b22cSJim Ingham     m_set_flags.Clear(eCondition);
474af26b22cSJim Ingham   }
475af26b22cSJim Ingham   else
476af26b22cSJim Ingham     m_set_flags.Set(eCondition);
477ec537a24SSean Callanan 
4783dbf346eSSean Callanan   m_condition_text.assign(condition);
4793dbf346eSSean Callanan   std::hash<std::string> hasher;
4803dbf346eSSean Callanan   m_condition_text_hash = hasher(m_condition_text);
48136f3b369SJim Ingham }
48236f3b369SJim Ingham 
GetConditionText(size_t * hash) const483b9c1b51eSKate Stone const char *BreakpointOptions::GetConditionText(size_t *hash) const {
484b9c1b51eSKate Stone   if (!m_condition_text.empty()) {
4853dbf346eSSean Callanan     if (hash)
4863dbf346eSSean Callanan       *hash = m_condition_text_hash;
4873dbf346eSSean Callanan 
4883dbf346eSSean Callanan     return m_condition_text.c_str();
489b9c1b51eSKate Stone   } else {
49016fd7511SEugene Zelenko     return nullptr;
49136f3b369SJim Ingham   }
4923dbf346eSSean Callanan }
49336f3b369SJim Ingham 
GetThreadSpecNoCreate() const494b9c1b51eSKate Stone const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const {
495d5b44036SJonas Devlieghere   return m_thread_spec_up.get();
4961b54c88cSJim Ingham }
4971b54c88cSJim Ingham 
GetThreadSpec()498b9c1b51eSKate Stone ThreadSpec *BreakpointOptions::GetThreadSpec() {
499d5b44036SJonas Devlieghere   if (m_thread_spec_up == nullptr) {
500e8b072d9SJim Ingham     m_set_flags.Set(eThreadSpec);
50106412daeSJonas Devlieghere     m_thread_spec_up = std::make_unique<ThreadSpec>();
502e8b072d9SJim Ingham   }
5031b54c88cSJim Ingham 
504d5b44036SJonas Devlieghere   return m_thread_spec_up.get();
5051b54c88cSJim Ingham }
5061b54c88cSJim Ingham 
SetThreadID(lldb::tid_t thread_id)507b9c1b51eSKate Stone void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) {
5081b54c88cSJim Ingham   GetThreadSpec()->SetTID(thread_id);
509af26b22cSJim Ingham   m_set_flags.Set(eThreadSpec);
51030fdc8d8SChris Lattner }
51130fdc8d8SChris Lattner 
SetThreadSpec(std::unique_ptr<ThreadSpec> & thread_spec_up)512778ef392SJim Ingham void BreakpointOptions::SetThreadSpec(
513778ef392SJim Ingham     std::unique_ptr<ThreadSpec> &thread_spec_up) {
514d5b44036SJonas Devlieghere   m_thread_spec_up = std::move(thread_spec_up);
515af26b22cSJim Ingham   m_set_flags.Set(eThreadSpec);
516778ef392SJim Ingham }
517778ef392SJim Ingham 
GetDescription(Stream * s,lldb::DescriptionLevel level) const518b9c1b51eSKate Stone void BreakpointOptions::GetDescription(Stream *s,
519b9c1b51eSKate Stone                                        lldb::DescriptionLevel level) const {
520b9c1b51eSKate Stone   // Figure out if there are any options not at their default value, and only
52105097246SAdrian Prantl   // print anything if there are:
5220136309fSJim Ingham 
523f08f5c99SJim Ingham   if (m_ignore_count != 0 || !m_enabled || m_one_shot || m_auto_continue ||
524b9c1b51eSKate Stone       (GetThreadSpecNoCreate() != nullptr &&
525b9c1b51eSKate Stone        GetThreadSpecNoCreate()->HasSpecification())) {
526b9c1b51eSKate Stone     if (level == lldb::eDescriptionLevelVerbose) {
5270136309fSJim Ingham       s->EOL();
5280136309fSJim Ingham       s->IndentMore();
5290136309fSJim Ingham       s->Indent();
5300136309fSJim Ingham       s->PutCString("Breakpoint Options:\n");
5310136309fSJim Ingham       s->IndentMore();
5320136309fSJim Ingham       s->Indent();
533b9c1b51eSKate Stone     } else
5340136309fSJim Ingham       s->PutCString(" Options: ");
5350136309fSJim Ingham 
5360136309fSJim Ingham     if (m_ignore_count > 0)
5370136309fSJim Ingham       s->Printf("ignore: %d ", m_ignore_count);
5380136309fSJim Ingham     s->Printf("%sabled ", m_enabled ? "en" : "dis");
5390136309fSJim Ingham 
540ca36cd16SJim Ingham     if (m_one_shot)
541ca36cd16SJim Ingham       s->Printf("one-shot ");
542ca36cd16SJim Ingham 
543f08f5c99SJim Ingham     if (m_auto_continue)
544f08f5c99SJim Ingham       s->Printf("auto-continue ");
545f08f5c99SJim Ingham 
546d5b44036SJonas Devlieghere     if (m_thread_spec_up)
547d5b44036SJonas Devlieghere       m_thread_spec_up->GetDescription(s, level);
5485e09c8c3SJim Ingham 
549b9c1b51eSKate Stone     if (level == lldb::eDescriptionLevelFull) {
5500136309fSJim Ingham       s->IndentLess();
5510136309fSJim Ingham       s->IndentMore();
5520136309fSJim Ingham     }
5530136309fSJim Ingham   }
5540136309fSJim Ingham 
555b9c1b51eSKate Stone   if (m_callback_baton_sp.get()) {
556b9c1b51eSKate Stone     if (level != eDescriptionLevelBrief) {
55796fda9baSJohnny Chen       s->EOL();
5584f728bfcSRaphael Isemann       m_callback_baton_sp->GetDescription(s->AsRawOstream(), level,
5594f728bfcSRaphael Isemann                                           s->GetIndentLevel());
56096fda9baSJohnny Chen     }
56196fda9baSJohnny Chen   }
562b9c1b51eSKate Stone   if (!m_condition_text.empty()) {
563b9c1b51eSKate Stone     if (level != eDescriptionLevelBrief) {
56436f3b369SJim Ingham       s->EOL();
5653dbf346eSSean Callanan       s->Printf("Condition: %s\n", m_condition_text.c_str());
56636f3b369SJim Ingham     }
56736f3b369SJim Ingham   }
5680136309fSJim Ingham }
5690136309fSJim Ingham 
GetDescription(llvm::raw_ostream & s,lldb::DescriptionLevel level,unsigned indentation) const570b9c1b51eSKate Stone void BreakpointOptions::CommandBaton::GetDescription(
5714f728bfcSRaphael Isemann     llvm::raw_ostream &s, lldb::DescriptionLevel level,
5724f728bfcSRaphael Isemann     unsigned indentation) const {
5734e4fbe82SZachary Turner   const CommandData *data = getItem();
57430fdc8d8SChris Lattner 
575b9c1b51eSKate Stone   if (level == eDescriptionLevelBrief) {
5764f728bfcSRaphael Isemann     s << ", commands = "
5774f728bfcSRaphael Isemann       << ((data && data->user_source.GetSize() > 0) ? "yes" : "no");
5780136309fSJim Ingham     return;
5790136309fSJim Ingham   }
5800136309fSJim Ingham 
5814f728bfcSRaphael Isemann   indentation += 2;
5824f728bfcSRaphael Isemann   s.indent(indentation);
5834f728bfcSRaphael Isemann   s << "Breakpoint commands";
584f7e07256SJim Ingham   if (data->interpreter != eScriptLanguageNone)
5854f728bfcSRaphael Isemann     s << llvm::formatv(" ({0}):\n",
5864f728bfcSRaphael Isemann                        ScriptInterpreter::LanguageToString(data->interpreter));
587f7e07256SJim Ingham   else
5884f728bfcSRaphael Isemann     s << ":\n";
5890136309fSJim Ingham 
5904f728bfcSRaphael Isemann   indentation += 2;
591b9c1b51eSKate Stone   if (data && data->user_source.GetSize() > 0) {
5924f728bfcSRaphael Isemann     for (llvm::StringRef str : data->user_source) {
5934f728bfcSRaphael Isemann       s.indent(indentation);
5944f728bfcSRaphael Isemann       s << str << "\n";
59530fdc8d8SChris Lattner     }
5964f728bfcSRaphael Isemann   } else
5974f728bfcSRaphael Isemann     s << "No commands.\n";
59830fdc8d8SChris Lattner }
599e14dc268SJim Ingham 
SetCommandDataCallback(std::unique_ptr<CommandData> & cmd_data)6004e4fbe82SZachary Turner void BreakpointOptions::SetCommandDataCallback(
60192d1960eSJim Ingham     std::unique_ptr<CommandData> &cmd_data) {
602f7e07256SJim Ingham   cmd_data->interpreter = eScriptLanguageNone;
6034e4fbe82SZachary Turner   auto baton_sp = std::make_shared<CommandBaton>(std::move(cmd_data));
604e14dc268SJim Ingham   SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, baton_sp);
605af26b22cSJim Ingham   m_set_flags.Set(eCallback);
606e14dc268SJim Ingham }
607e14dc268SJim Ingham 
BreakpointOptionsCallbackFunction(void * baton,StoppointCallbackContext * context,lldb::user_id_t break_id,lldb::user_id_t break_loc_id)608e14dc268SJim Ingham bool BreakpointOptions::BreakpointOptionsCallbackFunction(
609e14dc268SJim Ingham     void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id,
610e14dc268SJim Ingham     lldb::user_id_t break_loc_id) {
611e14dc268SJim Ingham   bool ret_value = true;
612e14dc268SJim Ingham   if (baton == nullptr)
613e14dc268SJim Ingham     return true;
614e14dc268SJim Ingham 
615e14dc268SJim Ingham   CommandData *data = (CommandData *)baton;
616e14dc268SJim Ingham   StringList &commands = data->user_source;
617e14dc268SJim Ingham 
618e14dc268SJim Ingham   if (commands.GetSize() > 0) {
619e14dc268SJim Ingham     ExecutionContext exe_ctx(context->exe_ctx_ref);
620e14dc268SJim Ingham     Target *target = exe_ctx.GetTargetPtr();
621e14dc268SJim Ingham     if (target) {
622e14dc268SJim Ingham       Debugger &debugger = target->GetDebugger();
623de019b88SJonas Devlieghere       CommandReturnObject result(debugger.GetUseColor());
624de019b88SJonas Devlieghere 
625e14dc268SJim Ingham       // Rig up the results secondary output stream to the debugger's, so the
62605097246SAdrian Prantl       // output will come out synchronously if the debugger is set up that way.
627e14dc268SJim Ingham       StreamSP output_stream(debugger.GetAsyncOutputStream());
628e14dc268SJim Ingham       StreamSP error_stream(debugger.GetAsyncErrorStream());
629e14dc268SJim Ingham       result.SetImmediateOutputStream(output_stream);
630e14dc268SJim Ingham       result.SetImmediateErrorStream(error_stream);
631e14dc268SJim Ingham 
632e14dc268SJim Ingham       CommandInterpreterRunOptions options;
633e14dc268SJim Ingham       options.SetStopOnContinue(true);
634e14dc268SJim Ingham       options.SetStopOnError(data->stop_on_error);
635e14dc268SJim Ingham       options.SetEchoCommands(true);
636e14dc268SJim Ingham       options.SetPrintResults(true);
637c0b48ab6SJonas Devlieghere       options.SetPrintErrors(true);
638e14dc268SJim Ingham       options.SetAddToHistory(false);
639e14dc268SJim Ingham 
64036de94cfSTatyana Krasnukha       debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx,
641e14dc268SJim Ingham                                                       options, result);
642e14dc268SJim Ingham       result.GetImmediateOutputStream()->Flush();
643e14dc268SJim Ingham       result.GetImmediateErrorStream()->Flush();
644e14dc268SJim Ingham     }
645e14dc268SJim Ingham   }
646e14dc268SJim Ingham   return ret_value;
647e14dc268SJim Ingham }
648b842f2ecSJim Ingham 
Clear()649b842f2ecSJim Ingham void BreakpointOptions::Clear()
650b842f2ecSJim Ingham {
651b842f2ecSJim Ingham   m_set_flags.Clear();
652d5b44036SJonas Devlieghere   m_thread_spec_up.release();
653b842f2ecSJim Ingham   m_one_shot = false;
654b842f2ecSJim Ingham   m_ignore_count = 0;
655b842f2ecSJim Ingham   m_auto_continue = false;
656b842f2ecSJim Ingham   m_callback = nullptr;
657b842f2ecSJim Ingham   m_callback_baton_sp.reset();
658b842f2ecSJim Ingham   m_baton_is_command_baton = false;
659b842f2ecSJim Ingham   m_callback_is_synchronous = false;
660b842f2ecSJim Ingham   m_enabled = false;
661b842f2ecSJim Ingham   m_condition_text.clear();
662b842f2ecSJim Ingham }
663