LLDB mainline
CommandObjectFrame.cpp
Go to the documentation of this file.
1//===-- CommandObjectFrame.cpp --------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
12#include "lldb/Host/Config.h"
29#include "lldb/Target/Target.h"
30#include "lldb/Target/Thread.h"
31#include "lldb/Utility/Args.h"
33
34#include <memory>
35#include <optional>
36#include <string>
37
38using namespace lldb;
39using namespace lldb_private;
40
41#pragma mark CommandObjectFrameDiagnose
42
43// CommandObjectFrameInfo
44
45// CommandObjectFrameDiagnose
46
47#define LLDB_OPTIONS_frame_diag
48#include "CommandOptions.inc"
49
51public:
52 class CommandOptions : public Options {
53 public:
55
56 ~CommandOptions() override = default;
57
58 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
59 ExecutionContext *execution_context) override {
61 const int short_option = m_getopt_table[option_idx].val;
62 switch (short_option) {
63 case 'r':
64 reg = ConstString(option_arg);
65 break;
66
67 case 'a': {
68 address.emplace();
69 if (option_arg.getAsInteger(0, *address)) {
70 address.reset();
72 "invalid address argument '%s'", option_arg.str().c_str());
73 }
74 } break;
75
76 case 'o': {
77 offset.emplace();
78 if (option_arg.getAsInteger(0, *offset)) {
79 offset.reset();
81 "invalid offset argument '%s'", option_arg.str().c_str());
82 }
83 } break;
84
85 default:
86 llvm_unreachable("Unimplemented option");
87 }
88
89 return error;
90 }
91
92 void OptionParsingStarting(ExecutionContext *execution_context) override {
93 address.reset();
94 reg.reset();
95 offset.reset();
96 }
97
98 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
99 return llvm::ArrayRef(g_frame_diag_options);
100 }
101
102 // Options.
103 std::optional<lldb::addr_t> address;
104 std::optional<ConstString> reg;
105 std::optional<int64_t> offset;
106 };
107
109 : CommandObjectParsed(interpreter, "frame diagnose",
110 "Try to determine what path the current stop "
111 "location used to get to a register or address",
112 nullptr,
113 eCommandRequiresThread | eCommandTryTargetAPILock |
114 eCommandProcessMustBeLaunched |
115 eCommandProcessMustBePaused) {
117 }
118
119 ~CommandObjectFrameDiagnose() override = default;
120
121 Options *GetOptions() override { return &m_options; }
122
123protected:
124 void DoExecute(Args &command, CommandReturnObject &result) override {
125 Thread *thread = m_exe_ctx.GetThreadPtr();
126 StackFrameSP frame_sp = thread->GetSelectedFrame(SelectMostRelevantFrame);
127
128 ValueObjectSP valobj_sp;
129
130 if (m_options.address) {
131 if (m_options.reg || m_options.offset) {
132 result.AppendError(
133 "`frame diagnose --address` is incompatible with other arguments.");
134 return;
135 }
136 valobj_sp = frame_sp->GuessValueForAddress(*m_options.address);
137 } else if (m_options.reg) {
138 valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
139 *m_options.reg, m_options.offset.value_or(0));
140 } else {
141 StopInfoSP stop_info_sp = thread->GetStopInfo();
142 if (!stop_info_sp) {
143 result.AppendError("no arguments provided, and no stop info");
144 return;
145 }
146
147 valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
148 }
149
150 if (!valobj_sp) {
151 result.AppendError("no diagnosis available");
152 return;
153 }
154
155 result.GetValueObjectList().Append(valobj_sp);
157 [&valobj_sp](ConstString type, ConstString var,
158 const DumpValueObjectOptions &opts,
159 Stream &stream) -> bool {
160 const ValueObject::GetExpressionPathFormat format = ValueObject::
161 GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
162 valobj_sp->GetExpressionPath(stream, format);
163 stream.PutCString(" =");
164 return true;
165 };
166
168 options.SetDeclPrintingHelper(helper);
169 // We've already handled the case where the value object sp is null, so
170 // this is just to make sure future changes don't skip that:
171 assert(valobj_sp.get() && "Must have a valid ValueObject to print");
172 ValueObjectPrinter printer(*valobj_sp, &result.GetOutputStream(), options);
173 if (llvm::Error error = printer.PrintValueObject())
174 result.AppendError(toString(std::move(error)));
175 }
176
178};
179
180#pragma mark CommandObjectFrameInfo
181
182// CommandObjectFrameInfo
183
185public:
187 : CommandObjectParsed(interpreter, "frame info",
188 "List information about the current "
189 "stack frame in the current thread.",
190 "frame info",
191 eCommandRequiresFrame | eCommandTryTargetAPILock |
192 eCommandProcessMustBeLaunched |
193 eCommandProcessMustBePaused) {}
194
195 ~CommandObjectFrameInfo() override = default;
196
197protected:
198 void DoExecute(Args &command, CommandReturnObject &result) override {
199 m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
201 }
202};
203
204#pragma mark CommandObjectFrameSelect
205
206// CommandObjectFrameSelect
207
208#define LLDB_OPTIONS_frame_select
209#include "CommandOptions.inc"
210
212public:
213 class CommandOptions : public Options {
214 public:
216
217 ~CommandOptions() override = default;
218
219 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
220 ExecutionContext *execution_context) override {
222 const int short_option = m_getopt_table[option_idx].val;
223 switch (short_option) {
224 case 'r': {
225 int32_t offset = 0;
226 if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
228 "invalid frame offset argument '%s'", option_arg.str().c_str());
229 } else
230 relative_frame_offset = offset;
231 break;
232 }
233
234 default:
235 llvm_unreachable("Unimplemented option");
236 }
237
238 return error;
239 }
240
241 void OptionParsingStarting(ExecutionContext *execution_context) override {
242 relative_frame_offset.reset();
243 }
244
245 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
246 return llvm::ArrayRef(g_frame_select_options);
247 }
248
249 std::optional<int32_t> relative_frame_offset;
250 };
251
253 : CommandObjectParsed(interpreter, "frame select",
254 "Select the current stack frame by "
255 "index from within the current thread "
256 "(see 'thread backtrace'.)",
257 nullptr,
258 eCommandRequiresThread | eCommandTryTargetAPILock |
259 eCommandProcessMustBeLaunched |
260 eCommandProcessMustBePaused) {
262 }
263
264 ~CommandObjectFrameSelect() override = default;
265
266 Options *GetOptions() override { return &m_options; }
267
268private:
269 void SkipHiddenFrames(Thread &thread, uint32_t frame_idx) {
270 uint32_t candidate_idx = frame_idx;
271 const unsigned max_depth = 12;
272 for (unsigned num_try = 0; num_try < max_depth; ++num_try) {
273 if (candidate_idx == 0 && *m_options.relative_frame_offset == -1) {
274 candidate_idx = UINT32_MAX;
275 break;
276 }
277 candidate_idx += *m_options.relative_frame_offset;
278 if (auto candidate_sp = thread.GetStackFrameAtIndex(candidate_idx)) {
279 if (candidate_sp->IsHidden())
280 continue;
281 // Now candidate_idx is the first non-hidden frame.
282 break;
283 }
284 candidate_idx = UINT32_MAX;
285 break;
286 };
287 if (candidate_idx != UINT32_MAX)
288 m_options.relative_frame_offset = candidate_idx - frame_idx;
289 }
290
291protected:
292 void DoExecute(Args &command, CommandReturnObject &result) override {
293 // No need to check "thread" for validity as eCommandRequiresThread ensures
294 // it is valid
295 Thread *thread = m_exe_ctx.GetThreadPtr();
296
297 uint32_t frame_idx = UINT32_MAX;
298 if (m_options.relative_frame_offset) {
299 // The one and only argument is a signed relative frame index
300 frame_idx = thread->GetSelectedFrameIndex(SelectMostRelevantFrame);
301 if (frame_idx == UINT32_MAX)
302 frame_idx = 0;
303
304 // If moving up/down by one, skip over hidden frames, unless we started
305 // in a hidden frame.
306 if ((*m_options.relative_frame_offset == 1 ||
307 *m_options.relative_frame_offset == -1)) {
308 if (auto current_frame_sp = thread->GetStackFrameAtIndex(frame_idx);
309 !current_frame_sp->IsHidden())
310 SkipHiddenFrames(*thread, frame_idx);
311 }
312
313 if (*m_options.relative_frame_offset < 0) {
314 if (static_cast<int32_t>(frame_idx) >=
315 -*m_options.relative_frame_offset)
316 frame_idx += *m_options.relative_frame_offset;
317 else {
318 if (frame_idx == 0) {
319 // If you are already at the bottom of the stack, then just warn
320 // and don't reset the frame.
321 result.AppendError("already at the bottom of the stack");
322 return;
323 } else
324 frame_idx = 0;
325 }
326 } else if (*m_options.relative_frame_offset > 0) {
327 // I don't want "up 20" where "20" takes you past the top of the stack
328 // to produce an error, but rather to just go to the top. OTOH, start
329 // by seeing if the requested frame exists, in which case we can avoid
330 // counting the stack here...
331 const uint32_t frame_requested =
332 frame_idx + *m_options.relative_frame_offset;
333 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_requested);
334 if (frame_sp)
335 frame_idx = frame_requested;
336 else {
337 // The request went past the stack, so handle that case:
338 const uint32_t num_frames = thread->GetStackFrameCount();
339 if (static_cast<int32_t>(num_frames - frame_idx) >
340 *m_options.relative_frame_offset)
341 frame_idx += *m_options.relative_frame_offset;
342 else {
343 if (frame_idx == num_frames - 1) {
344 // If we are already at the top of the stack, just warn and don't
345 // reset the frame.
346 result.AppendError("already at the top of the stack");
347 return;
348 } else
349 frame_idx = num_frames - 1;
350 }
351 }
352 }
353 } else {
354 if (command.GetArgumentCount() > 1) {
356 "too many arguments; expected frame-index, saw '%s'.\n",
357 command[0].c_str());
358 m_options.GenerateOptionUsage(
359 result.GetErrorStream(), *this,
360 GetCommandInterpreter().GetDebugger().GetTerminalWidth(),
361 GetCommandInterpreter().GetDebugger().GetUseColor());
362 return;
363 }
364
365 if (command.GetArgumentCount() == 1) {
366 if (command[0].ref().getAsInteger(0, frame_idx)) {
367 result.AppendErrorWithFormat("invalid frame index argument '%s'.",
368 command[0].c_str());
369 return;
370 }
371 } else if (command.GetArgumentCount() == 0) {
372 frame_idx = thread->GetSelectedFrameIndex(SelectMostRelevantFrame);
373 if (frame_idx == UINT32_MAX) {
374 frame_idx = 0;
375 }
376 }
377 }
378
379 bool success = thread->SetSelectedFrameByIndexNoisily(
380 frame_idx, result.GetOutputStream());
381 if (success) {
382 m_exe_ctx.SetFrameSP(thread->GetSelectedFrame(SelectMostRelevantFrame));
384 } else {
385 result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
386 frame_idx);
387 }
388 }
389
391};
392
393#pragma mark CommandObjectFrameVariable
394// List images with associated information
396public:
399 interpreter, "frame variable",
400 "Show variables for the current stack frame. Defaults to all "
401 "arguments and local variables in scope. Names of argument, "
402 "local, file static and file global variables can be specified.",
403 nullptr,
404 eCommandRequiresFrame | eCommandTryTargetAPILock |
405 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
406 eCommandRequiresProcess),
408 true), // Include the frame specific options by passing "true"
410 SetHelpLong(R"(
411Children of aggregate variables can be specified such as 'var->child.x'. In
412'frame variable', the operators -> and [] do not invoke operator overloads if
413they exist, but directly access the specified element. If you want to trigger
414operator overloads use the expression command to print the variable instead.
415
416It is worth noting that except for overloaded operators, when printing local
417variables 'expr local_var' and 'frame var local_var' produce the same results.
418However, 'frame variable' is more efficient, since it uses debug information and
419memory reads directly, rather than parsing and evaluating an expression, which
420may even involve JITing and running code in the target program.)");
421
430 m_option_group.Finalize();
431 }
432
433 ~CommandObjectFrameVariable() override = default;
434
435 Options *GetOptions() override { return &m_option_group; }
436
437protected:
438 llvm::StringRef GetScopeString(VariableSP var_sp) {
439 if (!var_sp)
440 return llvm::StringRef();
441
442 switch (var_sp->GetScope()) {
444 return "GLOBAL: ";
446 return "STATIC: ";
448 return "ARG: ";
450 return "LOCAL: ";
452 return "THREAD: ";
453 default:
454 break;
455 }
456
457 return llvm::StringRef();
458 }
459
460 /// Returns true if `scope` matches any of the options in `m_option_variable`.
461 bool ScopeRequested(lldb::ValueType scope) {
462 switch (scope) {
465 return m_option_variable.show_globals;
467 return m_option_variable.show_args;
469 return m_option_variable.show_locals;
475 case eValueTypeVTable:
477 return false;
478 }
479 llvm_unreachable("Unexpected scope value");
480 }
481
482 /// Finds all the variables in `all_variables` whose name matches `regex`,
483 /// inserting them into `matches`. Variables already contained in `matches`
484 /// are not inserted again.
485 /// Nullopt is returned in case of no matches.
486 /// A sub-range of `matches` with all newly inserted variables is returned.
487 /// This may be empty if all matches were already contained in `matches`.
488 std::optional<llvm::ArrayRef<VariableSP>>
490 VariableList &matches,
491 const VariableList &all_variables) {
492 bool any_matches = false;
493 const size_t previous_num_vars = matches.GetSize();
494
495 for (const VariableSP &var : all_variables) {
496 if (!var->NameMatches(regex) || !ScopeRequested(var->GetScope()))
497 continue;
498 any_matches = true;
499 matches.AddVariableIfUnique(var);
500 }
501
502 if (any_matches)
503 return matches.toArrayRef().drop_front(previous_num_vars);
504 return std::nullopt;
505 }
506
507 void DoExecute(Args &command, CommandReturnObject &result) override {
508 // No need to check "frame" for validity as eCommandRequiresFrame ensures
509 // it is valid
510 StackFrame *frame = m_exe_ctx.GetFramePtr();
511
512 Stream &s = result.GetOutputStream();
513
514 // Using a regex should behave like looking for an exact name match: it
515 // also finds globals.
516 m_option_variable.show_globals |= m_option_variable.use_regex;
517
518 // Be careful about the stack frame, if any summary formatter runs code, it
519 // might clear the StackFrameList for the thread. So hold onto a shared
520 // pointer to the frame so it stays alive.
521
523 VariableList *variable_list =
524 frame->GetVariableList(m_option_variable.show_globals, &error);
525
526 if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) {
527 result.AppendError(error.AsCString());
528 }
529
530 ValueObjectSP valobj_sp;
531
532 TypeSummaryImplSP summary_format_sp;
533 if (!m_option_variable.summary.IsCurrentValueEmpty())
535 ConstString(m_option_variable.summary.GetCurrentValue()),
536 summary_format_sp);
537 else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
538 summary_format_sp = std::make_shared<StringSummaryFormat>(
539 TypeSummaryImpl::Flags(),
540 m_option_variable.summary_string.GetCurrentValue());
541
542 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
544 summary_format_sp));
545
546 const SymbolContext &sym_ctx =
547 frame->GetSymbolContext(eSymbolContextFunction);
548 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
549 m_option_variable.show_globals = true;
550
551 if (variable_list) {
552 const Format format = m_option_format.GetFormat();
553 options.SetFormat(format);
554
555 if (!command.empty()) {
556 VariableList regex_var_list;
557
558 // If we have any args to the variable command, we will make variable
559 // objects from them...
560 for (auto &entry : command) {
561 if (m_option_variable.use_regex) {
562 llvm::StringRef name_str = entry.ref();
563 RegularExpression regex(name_str);
564 if (regex.IsValid()) {
565 std::optional<llvm::ArrayRef<VariableSP>> results =
566 findUniqueRegexMatches(regex, regex_var_list, *variable_list);
567 if (!results) {
569 "no variables matched the regular expression '%s'.",
570 entry.c_str());
571 continue;
572 }
573 for (const VariableSP &var_sp : *results) {
574 valobj_sp = frame->GetValueObjectForFrameVariable(
575 var_sp, m_varobj_options.use_dynamic);
576 if (valobj_sp) {
577 result.GetValueObjectList().Append(valobj_sp);
578
579 std::string scope_string;
580 if (m_option_variable.show_scope)
581 scope_string = GetScopeString(var_sp).str();
582
583 if (!scope_string.empty())
584 s.PutCString(scope_string);
585
586 if (m_option_variable.show_decl &&
587 var_sp->GetDeclaration().GetFile()) {
588 bool show_fullpaths = false;
589 bool show_module = true;
590 if (var_sp->DumpDeclaration(&s, show_fullpaths,
591 show_module))
592 s.PutCString(": ");
593 }
594 auto &strm = result.GetOutputStream();
595 if (llvm::Error error = valobj_sp->Dump(strm, options))
596 result.AppendError(toString(std::move(error)));
597 }
598 }
599 } else {
600 if (llvm::Error err = regex.GetError())
601 result.AppendError(llvm::toString(std::move(err)));
602 else
604 "unknown regex error when compiling '%s'", entry.c_str());
605 }
606 } else // No regex, either exact variable names or variable
607 // expressions.
608 {
610 uint32_t expr_path_options =
615 lldb::VariableSP var_sp;
616 valobj_sp = frame->GetValueForVariableExpressionPath(
617 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
618 var_sp, error);
619 if (valobj_sp) {
620 result.GetValueObjectList().Append(valobj_sp);
621
622 std::string scope_string;
623 if (m_option_variable.show_scope)
624 scope_string = GetScopeString(var_sp).str();
625
626 if (!scope_string.empty())
627 s.PutCString(scope_string);
628 if (m_option_variable.show_decl && var_sp &&
629 var_sp->GetDeclaration().GetFile()) {
630 var_sp->GetDeclaration().DumpStopContext(&s, false);
631 s.PutCString(": ");
632 }
633
634 options.SetFormat(format);
635 options.SetVariableFormatDisplayLanguage(
636 valobj_sp->GetPreferredDisplayLanguage());
637
638 Stream &output_stream = result.GetOutputStream();
639 options.SetRootValueObjectName(
640 valobj_sp->GetParent() ? entry.c_str() : nullptr);
641 // Check only the `error` argument, because doing
642 // `valobj_sp->GetError()` will update the value and potentially
643 // return a new error that happens during the update, even if
644 // `GetValueForVariableExpressionPath` reported no errors.
645 if (error.Fail()) {
647 result.SetError(error.takeError());
648 } else {
649 // If there is an error while updating the value, it will be
650 // printed here as the contents of the value, e.g.
651 // `(int) *((int*)0) = <parent is NULL>`
652 if (llvm::Error error = valobj_sp->Dump(output_stream, options))
653 result.AppendError(toString(std::move(error)));
654 }
655
656 } else {
657 if (auto error_cstr = error.AsCString(nullptr))
658 result.AppendError(error_cstr);
659 else
661 "unable to find any variable expression path that matches "
662 "'%s'.",
663 entry.c_str());
664 }
665 }
666 }
667 } else // No command arg specified. Use variable_list, instead.
668 {
669 const size_t num_variables = variable_list->GetSize();
670 if (num_variables > 0) {
671 for (size_t i = 0; i < num_variables; i++) {
672 VariableSP var_sp = variable_list->GetVariableAtIndex(i);
673 if (!ScopeRequested(var_sp->GetScope()))
674 continue;
675 std::string scope_string;
676 if (m_option_variable.show_scope)
677 scope_string = GetScopeString(var_sp).str();
678
679 // Use the variable object code to make sure we are using the same
680 // APIs as the public API will be using...
681 valobj_sp = frame->GetValueObjectForFrameVariable(
682 var_sp, m_varobj_options.use_dynamic);
683 if (valobj_sp) {
684 result.GetValueObjectList().Append(valobj_sp);
685
686 // When dumping all variables, don't print any variables that are
687 // not in scope to avoid extra unneeded output
688 if (valobj_sp->IsInScope()) {
689 if (!valobj_sp->GetTargetSP()
690 ->GetDisplayRuntimeSupportValues() &&
691 valobj_sp->IsRuntimeSupportValue())
692 continue;
693
694 if (!scope_string.empty())
695 s.PutCString(scope_string);
696
697 if (m_option_variable.show_decl &&
698 var_sp->GetDeclaration().GetFile()) {
699 var_sp->GetDeclaration().DumpStopContext(&s, false);
700 s.PutCString(": ");
701 }
702
703 options.SetFormat(format);
704 options.SetVariableFormatDisplayLanguage(
705 valobj_sp->GetPreferredDisplayLanguage());
706 options.SetRootValueObjectName(
707 var_sp ? var_sp->GetName().AsCString(nullptr) : nullptr);
708 if (llvm::Error error =
709 valobj_sp->Dump(result.GetOutputStream(), options))
710 result.AppendError(toString(std::move(error)));
711 }
712 }
713 }
714 }
715 }
716 if (result.GetStatus() != eReturnStatusFailed)
718 }
719
720 if (m_option_variable.show_recognized_args) {
721 auto recognized_frame = frame->GetRecognizedFrame();
722 if (recognized_frame) {
723 ValueObjectListSP recognized_arg_list =
724 recognized_frame->GetRecognizedArguments();
725 if (recognized_arg_list) {
726 for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
727 result.GetValueObjectList().Append(rec_value_sp);
728 options.SetFormat(m_option_format.GetFormat());
729 options.SetVariableFormatDisplayLanguage(
730 rec_value_sp->GetPreferredDisplayLanguage());
731 options.SetRootValueObjectName(
732 rec_value_sp->GetName().AsCString(nullptr));
733 if (llvm::Error error =
734 rec_value_sp->Dump(result.GetOutputStream(), options))
735 result.AppendError(toString(std::move(error)));
736 }
737 }
738 }
739 }
740
741 m_interpreter.PrintWarningsIfNecessary(result.GetOutputStream(),
744 // Increment statistics.
746 if (result.Succeeded())
747 target_stats.GetFrameVariableStats().NotifySuccess();
748 else
749 target_stats.GetFrameVariableStats().NotifyFailure();
750 }
751
756};
757
758#pragma mark CommandObjectFrameRecognizer
759
760#define LLDB_OPTIONS_frame_recognizer_add
761#include "CommandOptions.inc"
762
764private:
765 class CommandOptions : public Options {
766 public:
767 CommandOptions() = default;
768 ~CommandOptions() override = default;
769
770 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
771 ExecutionContext *execution_context) override {
773 const int short_option = m_getopt_table[option_idx].val;
774
775 switch (short_option) {
776 case 'f': {
777 bool value, success;
778 value = OptionArgParser::ToBoolean(option_arg, true, &success);
779 if (success) {
781 } else {
783 "invalid boolean value '%s' passed for -f option",
784 option_arg.str().c_str());
785 }
786 } break;
787 case 'l':
788 m_class_name = std::string(option_arg);
789 break;
790 case 's':
791 m_module = std::string(option_arg);
792 break;
793 case 'n':
794 m_symbols.push_back(std::string(option_arg));
795 break;
796 case 'x':
797 m_regex = true;
798 break;
799 default:
800 llvm_unreachable("Unimplemented option");
801 }
802
803 return error;
804 }
805
806 void OptionParsingStarting(ExecutionContext *execution_context) override {
807 m_module = "";
808 m_symbols.clear();
809 m_class_name = "";
810 m_regex = false;
812 }
813
814 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
815 return llvm::ArrayRef(g_frame_recognizer_add_options);
816 }
817
818 // Instance variables to hold the values for command options.
819 std::string m_class_name;
820 std::string m_module;
821 std::vector<std::string> m_symbols;
824 };
825
827
828 Options *GetOptions() override { return &m_options; }
829
830protected:
831 void DoExecute(Args &command, CommandReturnObject &result) override;
832
833public:
835 : CommandObjectParsed(interpreter, "frame recognizer add",
836 "Add a new frame recognizer.", nullptr) {
837 SetHelpLong(R"(
838Frame recognizers allow for retrieving information about special frames based on
839ABI, arguments or other special properties of that frame, even without source
840code or debug info. Currently, one use case is to extract function arguments
841that would otherwise be unaccesible, or augment existing arguments.
842
843Adding a custom frame recognizer is possible by implementing a Python class
844and using the 'frame recognizer add' command. The Python class should have a
845'get_recognized_arguments' method and it will receive an argument of type
846lldb.SBFrame representing the current frame that we are trying to recognize.
847The method should return a (possibly empty) list of lldb.SBValue objects that
848represent the recognized arguments.
849
850An example of a recognizer that retrieves the file descriptor values from libc
851functions 'read', 'write' and 'close' follows:
852
853 class LibcFdRecognizer(object):
854 def get_recognized_arguments(self, frame):
855 if frame.name in ["read", "write", "close"]:
856 fd = frame.EvaluateExpression("$arg1").unsigned
857 target = frame.thread.process.target
858 value = target.CreateValueFromExpression("fd", "(int)%d" % fd)
859 return [value]
860 return []
861
862The file containing this implementation can be imported via 'command script
863import' and then we can register this recognizer with 'frame recognizer add'.
864It's important to restrict the recognizer to the libc library (which is
865libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
866in other modules:
867
868(lldb) command script import .../fd_recognizer.py
869(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
870
871When the program is stopped at the beginning of the 'read' function in libc, we
872can view the recognizer arguments in 'frame variable':
873
874(lldb) b read
875(lldb) r
876Process 1234 stopped
877* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
878 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
879(lldb) frame variable
880(int) fd = 3
881
882 )");
883 }
884 ~CommandObjectFrameRecognizerAdd() override = default;
885};
886
888 CommandReturnObject &result) {
889#if LLDB_ENABLE_PYTHON
890 if (m_options.m_class_name.empty()) {
892 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
893 return;
894 }
895
896 if (m_options.m_module.empty()) {
897 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
898 m_cmd_name.c_str());
899 return;
900 }
901
902 if (m_options.m_symbols.empty()) {
904 "%s needs at least one symbol name (-n argument).\n",
905 m_cmd_name.c_str());
906 return;
907 }
908
909 if (m_options.m_regex && m_options.m_symbols.size() > 1) {
911 "%s needs only one symbol regular expression (-n argument).\n",
912 m_cmd_name.c_str());
913 return;
914 }
915
917
918 if (interpreter &&
919 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
920 result.AppendWarning("the provided class does not exist - please define it "
921 "before attempting to use this frame recognizer");
922 }
923
924 StackFrameRecognizerSP recognizer_sp =
926 interpreter, m_options.m_class_name.c_str()));
927 if (m_options.m_regex) {
928 auto module = std::make_shared<RegularExpression>(m_options.m_module);
929 auto func =
930 std::make_shared<RegularExpression>(m_options.m_symbols.front());
932 recognizer_sp, module, func, Mangled::NamePreference::ePreferDemangled,
933 m_options.m_first_instruction_only);
934 } else {
935 auto module = ConstString(m_options.m_module);
936 std::vector<ConstString> symbols(m_options.m_symbols.begin(),
937 m_options.m_symbols.end());
939 recognizer_sp, module, symbols,
941 m_options.m_first_instruction_only);
942 }
943#endif
944
946}
947
949public:
951 : CommandObjectParsed(interpreter, "frame recognizer clear",
952 "Delete all frame recognizers.", nullptr) {}
953
955
956protected:
961};
962
963static void
964PrintRecognizerDetails(Stream &strm, const std::string &name, bool enabled,
965 const std::string &module,
966 llvm::ArrayRef<lldb_private::ConstString> symbols,
967 Mangled::NamePreference symbol_mangling, bool regexp) {
968 if (!enabled)
969 strm << "[disabled] ";
970
971 strm << name << ", ";
972
973 if (!module.empty())
974 strm << "module " << module << ", ";
975
976 switch (symbol_mangling) {
977 case Mangled::NamePreference ::ePreferMangled:
978 strm << "mangled symbol ";
979 break;
980 case Mangled::NamePreference ::ePreferDemangled:
981 strm << "demangled symbol ";
982 break;
983 case Mangled::NamePreference ::ePreferDemangledWithoutArguments:
984 strm << "demangled (no args) symbol ";
985 break;
986 }
987
988 if (regexp)
989 strm << "regex ";
990
991 llvm::interleaveComma(symbols, strm);
992}
993
994// Base class for commands which accept a single frame recognizer as an argument
996public:
998 const char *name,
999 const char *help = nullptr,
1000 const char *syntax = nullptr,
1001 uint32_t flags = 0)
1002 : CommandObjectParsed(interpreter, name, help, syntax, flags) {
1004 }
1005
1006 void
1008 OptionElementVector &opt_element_vector) override {
1009 if (request.GetCursorIndex() != 0)
1010 return;
1011
1013 [&request](uint32_t rid, bool enabled, std::string rname,
1014 std::string module,
1015 llvm::ArrayRef<lldb_private::ConstString> symbols,
1016 Mangled::NamePreference symbol_mangling, bool regexp) {
1017 StreamString strm;
1018 if (rname.empty())
1019 rname = "(internal)";
1020
1021 PrintRecognizerDetails(strm, rname, enabled, module, symbols,
1022 symbol_mangling, regexp);
1023
1024 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
1025 });
1026 }
1027
1029 uint32_t recognizer_id) = 0;
1030
1031 void DoExecute(Args &command, CommandReturnObject &result) override {
1032 uint32_t recognizer_id;
1033 if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
1034 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
1035 command.GetArgumentAtIndex(0));
1036 return;
1037 }
1038
1039 DoExecuteWithId(result, recognizer_id);
1040 }
1041};
1042
1045public:
1048 interpreter, "frame recognizer enable",
1049 "Enable a frame recognizer by id.", nullptr) {
1051 }
1052
1054
1055protected:
1057 uint32_t recognizer_id) override {
1058 auto &recognizer_mgr = GetTarget().GetFrameRecognizerManager();
1059 if (!recognizer_mgr.SetEnabledForID(recognizer_id, true)) {
1060 result.AppendErrorWithFormat("'%u' is not a valid recognizer id.\n",
1061 recognizer_id);
1062 return;
1063 }
1065 }
1066};
1067
1070public:
1073 interpreter, "frame recognizer disable",
1074 "Disable a frame recognizer by id.", nullptr) {
1076 }
1077
1079
1080protected:
1082 uint32_t recognizer_id) override {
1083 auto &recognizer_mgr = GetTarget().GetFrameRecognizerManager();
1084 if (!recognizer_mgr.SetEnabledForID(recognizer_id, false)) {
1085 result.AppendErrorWithFormat("'%u' is not a valid recognizer id.\n",
1086 recognizer_id);
1087 return;
1088 }
1090 }
1091};
1092
1095public:
1098 interpreter, "frame recognizer delete",
1099 "Delete an existing frame recognizer by id.", nullptr) {
1101 }
1102
1104
1105protected:
1107 uint32_t recognizer_id) override {
1108 auto &recognizer_mgr = GetTarget().GetFrameRecognizerManager();
1109 if (!recognizer_mgr.RemoveRecognizerWithID(recognizer_id)) {
1110 result.AppendErrorWithFormat("'%u' is not a valid recognizer id.\n",
1111 recognizer_id);
1112 return;
1113 }
1115 }
1116};
1117
1119public:
1121 : CommandObjectParsed(interpreter, "frame recognizer list",
1122 "Show a list of active frame recognizers.",
1123 nullptr) {}
1124
1126
1127protected:
1128 void DoExecute(Args &command, CommandReturnObject &result) override {
1129 bool any_printed = false;
1131 [&result,
1132 &any_printed](uint32_t recognizer_id, bool enabled, std::string name,
1133 std::string module, llvm::ArrayRef<ConstString> symbols,
1134 Mangled::NamePreference symbol_mangling, bool regexp) {
1135 Stream &stream = result.GetOutputStream();
1136
1137 if (name.empty())
1138 name = "(internal)";
1139
1140 stream << std::to_string(recognizer_id) << ": ";
1141 PrintRecognizerDetails(stream, name, enabled, module, symbols,
1142 symbol_mangling, regexp);
1143
1144 stream.EOL();
1145 stream.Flush();
1146
1147 any_printed = true;
1148 });
1149
1150 if (any_printed)
1152 else {
1153 result.GetOutputStream().PutCString("no matching results found.\n");
1155 }
1156 }
1157};
1158
1160public:
1163 interpreter, "frame recognizer info",
1164 "Show which frame recognizer is applied a stack frame (if any).",
1165 nullptr) {
1167 }
1168
1170
1171protected:
1172 void DoExecute(Args &command, CommandReturnObject &result) override {
1173 const char *frame_index_str = command.GetArgumentAtIndex(0);
1174 uint32_t frame_index;
1175 if (!llvm::to_integer(frame_index_str, frame_index)) {
1176 result.AppendErrorWithFormat("'%s' is not a valid frame index.",
1177 frame_index_str);
1178 return;
1179 }
1180
1181 Process *process = m_exe_ctx.GetProcessPtr();
1182 if (process == nullptr) {
1183 result.AppendError("no process");
1184 return;
1185 }
1186 Thread *thread = m_exe_ctx.GetThreadPtr();
1187 if (thread == nullptr) {
1188 result.AppendError("no thread");
1189 return;
1190 }
1191 if (command.GetArgumentCount() != 1) {
1192 result.AppendErrorWithFormat(
1193 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1194 return;
1195 }
1196
1197 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1198 if (!frame_sp) {
1199 result.AppendErrorWithFormat("no frame with index %u", frame_index);
1200 return;
1201 }
1202
1203 auto recognizer =
1205
1206 Stream &output_stream = result.GetOutputStream();
1207 output_stream.Printf("frame %d ", frame_index);
1208 if (recognizer) {
1209 output_stream << "is recognized by ";
1210 output_stream << recognizer->GetName();
1211 } else {
1212 output_stream << "not recognized by any recognizer";
1213 }
1214 output_stream.EOL();
1216 }
1217};
1218
1220public:
1223 interpreter, "frame recognizer",
1224 "Commands for editing and viewing frame recognizers.",
1225 "frame recognizer [<sub-command-options>] ") {
1227 interpreter)));
1229 interpreter)));
1231 interpreter)));
1233 "enable",
1236 "disable",
1239 "delete",
1242 "clear",
1244 }
1245
1246 ~CommandObjectFrameRecognizer() override = default;
1247};
1248
1249#pragma mark CommandObjectMultiwordFrame
1250
1251// CommandObjectMultiwordFrame
1252
1254 CommandInterpreter &interpreter)
1255 : CommandObjectMultiword(interpreter, "frame",
1256 "Commands for selecting and "
1257 "examining the current "
1258 "thread's stack frames.",
1259 "frame <subcommand> [<subcommand-options>]") {
1260 LoadSubCommand("diagnose",
1262 LoadSubCommand("info",
1263 CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1264 LoadSubCommand("select",
1265 CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1266 LoadSubCommand("variable",
1268#if LLDB_ENABLE_PYTHON
1270 interpreter)));
1271#endif
1272}
1273
static void PrintRecognizerDetails(Stream &strm, const std::string &name, bool enabled, const std::string &module, llvm::ArrayRef< lldb_private::ConstString > symbols, Mangled::NamePreference symbol_mangling, bool regexp)
static llvm::raw_ostream & error(Stream &strm)
void OptionParsingStarting(ExecutionContext *execution_context) override
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
~CommandObjectFrameDiagnose() override=default
CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
void DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectFrameInfo(CommandInterpreter &interpreter)
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameInfo() override=default
void OptionParsingStarting(ExecutionContext *execution_context) override
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameRecognizerAdd() override=default
CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerClear() override=default
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameRecognizerDelete() override=default
CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
void DoExecuteWithId(CommandReturnObject &result, uint32_t recognizer_id) override
CommandObjectFrameRecognizerDisable(CommandInterpreter &interpreter)
void DoExecuteWithId(CommandReturnObject &result, uint32_t recognizer_id) override
~CommandObjectFrameRecognizerDisable() override=default
void DoExecuteWithId(CommandReturnObject &result, uint32_t recognizer_id) override
CommandObjectFrameRecognizerEnable(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerEnable() override=default
CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerInfo() override=default
void DoExecute(Args &command, CommandReturnObject &result) override
CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
~CommandObjectFrameRecognizerList() override=default
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectFrameRecognizer() override=default
CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override
Set the value of an option.
void OptionParsingStarting(ExecutionContext *execution_context) override
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
void SkipHiddenFrames(Thread &thread, uint32_t frame_idx)
~CommandObjectFrameSelect() override=default
CommandObjectFrameSelect(CommandInterpreter &interpreter)
Options * GetOptions() override
void DoExecute(Args &command, CommandReturnObject &result) override
OptionGroupVariable m_option_variable
OptionGroupValueObjectDisplay m_varobj_options
bool ScopeRequested(lldb::ValueType scope)
Returns true if scope matches any of the options in m_option_variable.
llvm::StringRef GetScopeString(VariableSP var_sp)
std::optional< llvm::ArrayRef< VariableSP > > findUniqueRegexMatches(RegularExpression &regex, VariableList &matches, const VariableList &all_variables)
Finds all the variables in all_variables whose name matches regex, inserting them into matches.
~CommandObjectFrameVariable() override=default
CommandObjectFrameVariable(CommandInterpreter &interpreter)
void DoExecute(Args &command, CommandReturnObject &result) override
void DoExecute(Args &command, CommandReturnObject &result) override
void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override
The default version handles argument definitions that have only one argument type,...
CommandObjectWithFrameRecognizerArg(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
virtual void DoExecuteWithId(CommandReturnObject &result, uint32_t recognizer_id)=0
A command line argument class.
Definition Args.h:33
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition Args.h:120
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
Definition Args.cpp:273
bool empty() const
Definition Args.h:122
CommandObjectMultiwordFrame(CommandInterpreter &interpreter)
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
CommandObjectMultiword(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
CommandObjectParsed(CommandInterpreter &interpreter, const char *name, const char *help=nullptr, const char *syntax=nullptr, uint32_t flags=0)
virtual void SetHelpLong(llvm::StringRef str)
void AddSimpleArgumentList(lldb::CommandArgumentType arg_type, ArgumentRepetitionType repetition_type=eArgRepeatPlain)
CommandInterpreter & GetCommandInterpreter()
CommandInterpreter & m_interpreter
void AppendError(llvm::StringRef in_string)
const ValueObjectList & GetValueObjectList() const
void SetStatus(lldb::ReturnStatus status)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
void AppendWarning(llvm::StringRef in_string)
"lldb/Utility/ArgCompletionRequest.h"
void TryCompleteCurrentArg(llvm::StringRef completion, llvm::StringRef description="")
Adds a possible completion string if the completion would complete the current argument.
A uniqued constant string class.
Definition ConstString.h:40
static bool GetSummaryFormat(ConstString type, lldb::TypeSummaryImplSP &entry)
ScriptInterpreter * GetScriptInterpreter(bool can_create=true, std::optional< lldb::ScriptLanguage > language={})
std::function< bool(ConstString, ConstString, const DumpValueObjectOptions &, Stream &)> DeclPrintingHelper
DumpValueObjectOptions & SetDeclPrintingHelper(DeclPrintingHelper helper)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
bool IsTopLevelFunction()
Get whether this function represents a 'top-level' function.
Definition Function.cpp:524
static const uint32_t OPTION_GROUP_GDB_FMT
static const uint32_t OPTION_GROUP_FORMAT
A command line option parsing protocol class.
Definition Options.h:58
std::vector< Option > m_getopt_table
Definition Options.h:198
A plug-in interface definition class for debugging a process.
Definition Process.h:355
bool IsValid() const
Test if this object contains a valid regular expression.
llvm::Error GetError() const
Return an error if the regular expression failed to compile.
virtual bool CheckObjectExists(const char *name)
Python implementation for frame recognizers.
void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, ConstString module, llvm::ArrayRef< ConstString > symbols, Mangled::NamePreference symbol_mangling, bool first_instruction_only=true)
Add a new recognizer that triggers on a given symbol name.
void ForEach(std::function< void(uint32_t recognizer_id, bool enabled, std::string recognizer_name, std::string module, llvm::ArrayRef< ConstString > symbols, Mangled::NamePreference name_preference, bool regexp)> const &callback)
lldb::StackFrameRecognizerSP GetRecognizerForFrame(lldb::StackFrameSP frame)
virtual lldb::ValueObjectSP GetValueForVariableExpressionPath(llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, uint32_t options, lldb::VariableSP &var_sp, Status &error, lldb::DILMode mode=lldb::eDILModeFull)
Create a ValueObject for a variable name / pathname, possibly including simple dereference/child sele...
@ eExpressionPathOptionsInspectAnonymousUnions
Definition StackFrame.h:59
@ eExpressionPathOptionsAllowDirectIVarAccess
Definition StackFrame.h:58
virtual VariableList * GetVariableList(bool get_file_globals, Status *error_ptr)
Retrieve the list of variables whose scope either:
virtual lldb::ValueObjectSP GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic)
Create a ValueObject for a given Variable in this StackFrame.
virtual const SymbolContext & GetSymbolContext(lldb::SymbolContextItem resolve_scope)
Provide a SymbolContext for this StackFrame's current pc value.
virtual lldb::RecognizedStackFrameSP GetRecognizedFrame()
An error handling class.
Definition Status.h:118
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
static lldb::ValueObjectSP GetCrashingDereference(lldb::StopInfoSP &stop_info_sp, lldb::addr_t *crashing_address=nullptr)
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
Definition Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:132
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
virtual void Flush()=0
Flush the stream.
size_t EOL()
Output and End of Line character to the stream.
Definition Stream.cpp:153
Function * function
The Function for a given query.
A class that represents statistics for a since lldb_private::Target.
Definition Statistics.h:312
StatsSuccessFail & GetFrameVariableStats()
Definition Statistics.h:327
TargetStats & GetStatistics()
Definition Target.h:1895
StackFrameRecognizerManager & GetFrameRecognizerManager()
Definition Target.h:1718
void Append(const lldb::ValueObjectSP &val_obj_sp)
bool AddVariableIfUnique(const lldb::VariableSP &var_sp)
lldb::VariableSP GetVariableAtIndex(size_t idx) const
llvm::ArrayRef< lldb::VariableSP > toArrayRef()
#define LLDB_OPT_SET_1
#define LLDB_OPT_SET_ALL
#define UINT32_MAX
@ SelectMostRelevantFrame
A class that represents a running process on the host machine.
std::vector< OptionArgElement > OptionElementVector
Definition Options.h:43
std::string toString(FormatterBytecode::OpCodes op)
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::TypeSummaryImpl > TypeSummaryImplSP
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Format
Display format definitions.
std::shared_ptr< lldb_private::ValueObjectList > ValueObjectListSP
@ eReturnStatusFailed
@ eReturnStatusSuccessFinishResult
@ eReturnStatusSuccessFinishNoResult
@ eArgTypeRecognizerID
std::shared_ptr< lldb_private::Variable > VariableSP
std::shared_ptr< lldb_private::StackFrameRecognizer > StackFrameRecognizerSP
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
@ eValueTypeVTableEntry
function pointer in virtual function table
@ eValueTypeVTable
virtual function table
@ eValueTypeVariableGlobal
globals variable
@ eValueTypeConstResult
constant result variables
@ eValueTypeVariableLocal
function local variables
@ eValueTypeVariableArgument
function argument variables
@ eValueTypeRegister
stack frame register value
@ eValueTypeVariableStatic
static variable
@ eValueTypeRegisterSet
A collection of stack frame register values.
@ eValueTypeVariableThreadLocal
thread local storage variable
static bool ToBoolean(llvm::StringRef s, bool fail_value, bool *success_ptr)