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