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