1420 lines · cpp
1//===-- Options.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Interpreter/Options.h"10 11#include <algorithm>12#include <bitset>13#include <map>14#include <set>15 16#include "lldb/Host/OptionParser.h"17#include "lldb/Host/common/DiagnosticsRendering.h"18#include "lldb/Interpreter/CommandCompletions.h"19#include "lldb/Interpreter/CommandInterpreter.h"20#include "lldb/Interpreter/CommandObject.h"21#include "lldb/Interpreter/CommandReturnObject.h"22#include "lldb/Target/Target.h"23#include "lldb/Utility/AnsiTerminal.h"24#include "lldb/Utility/StreamString.h"25#include "llvm/ADT/STLExtras.h"26 27using namespace lldb;28using namespace lldb_private;29 30namespace lldb_private {31 32/// An llvm::Error that represents an option parsing diagnostic.33class OptionParseError34 : public llvm::ErrorInfo<OptionParseError, DiagnosticError> {35 std::vector<DiagnosticDetail> m_details;36 37public:38 using llvm::ErrorInfo<OptionParseError, DiagnosticError>::ErrorInfo;39 OptionParseError(DiagnosticDetail detail)40 : ErrorInfo(std::error_code(EINVAL, std::generic_category())),41 m_details({detail}) {}42 OptionParseError(const Args::ArgEntry &arg, std::string msg)43 : ErrorInfo(std::error_code(EINVAL, std::generic_category())) {44 DiagnosticDetail::SourceLocation sloc;45 if (auto pos = arg.GetPos()) {46 uint16_t len = arg.GetLength();47 sloc = {FileSpec{}, 1, *pos, len, false, true};48 }49 m_details.push_back(DiagnosticDetail{sloc, lldb::eSeverityError, msg, msg});50 }51 std::unique_ptr<CloneableError> Clone() const override {52 return std::make_unique<OptionParseError>(m_details[0]);53 }54 llvm::ArrayRef<DiagnosticDetail> GetDetails() const override {55 return m_details;56 }57 static char ID;58};59 60char OptionParseError::ID;61 62} // namespace lldb_private63 64// Options65Options::Options() { BuildValidOptionSets(); }66 67Options::~Options() = default;68 69void Options::NotifyOptionParsingStarting(ExecutionContext *execution_context) {70 m_seen_options.clear();71 // Let the subclass reset its option values72 OptionParsingStarting(execution_context);73}74 75Status76Options::NotifyOptionParsingFinished(ExecutionContext *execution_context) {77 return OptionParsingFinished(execution_context);78}79 80void Options::OptionSeen(int option_idx) { m_seen_options.insert(option_idx); }81 82// Returns true is set_a is a subset of set_b; Otherwise returns false.83 84bool Options::IsASubset(const OptionSet &set_a, const OptionSet &set_b) {85 bool is_a_subset = true;86 OptionSet::const_iterator pos_a;87 OptionSet::const_iterator pos_b;88 89 // set_a is a subset of set_b if every member of set_a is also a member of90 // set_b91 92 for (pos_a = set_a.begin(); pos_a != set_a.end() && is_a_subset; ++pos_a) {93 pos_b = set_b.find(*pos_a);94 if (pos_b == set_b.end())95 is_a_subset = false;96 }97 98 return is_a_subset;99}100 101// Returns the set difference set_a - set_b, i.e. { x | ElementOf (x, set_a) &&102// !ElementOf (x, set_b) }103 104size_t Options::OptionsSetDiff(const OptionSet &set_a, const OptionSet &set_b,105 OptionSet &diffs) {106 size_t num_diffs = 0;107 OptionSet::const_iterator pos_a;108 OptionSet::const_iterator pos_b;109 110 for (pos_a = set_a.begin(); pos_a != set_a.end(); ++pos_a) {111 pos_b = set_b.find(*pos_a);112 if (pos_b == set_b.end()) {113 ++num_diffs;114 diffs.insert(*pos_a);115 }116 }117 118 return num_diffs;119}120 121// Returns the union of set_a and set_b. Does not put duplicate members into122// the union.123 124void Options::OptionsSetUnion(const OptionSet &set_a, const OptionSet &set_b,125 OptionSet &union_set) {126 OptionSet::const_iterator pos;127 OptionSet::iterator pos_union;128 129 // Put all the elements of set_a into the union.130 131 for (pos = set_a.begin(); pos != set_a.end(); ++pos)132 union_set.insert(*pos);133 134 // Put all the elements of set_b that are not already there into the union.135 for (pos = set_b.begin(); pos != set_b.end(); ++pos) {136 pos_union = union_set.find(*pos);137 if (pos_union == union_set.end())138 union_set.insert(*pos);139 }140}141 142// This is called in the Options constructor, though we could call it lazily if143// that ends up being a performance problem.144 145void Options::BuildValidOptionSets() {146 // Check to see if we already did this.147 if (m_required_options.size() != 0)148 return;149 150 // Check to see if there are any options.151 int num_options = NumCommandOptions();152 if (num_options == 0)153 return;154 155 auto opt_defs = GetDefinitions();156 m_required_options.resize(1);157 m_optional_options.resize(1);158 159 // First count the number of option sets we've got. Ignore160 // LLDB_ALL_OPTION_SETS...161 162 uint32_t num_option_sets = 0;163 164 for (const auto &def : opt_defs) {165 uint32_t this_usage_mask = def.usage_mask;166 if (this_usage_mask == LLDB_OPT_SET_ALL) {167 if (num_option_sets == 0)168 num_option_sets = 1;169 } else {170 for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) {171 if (this_usage_mask & (1 << j)) {172 if (num_option_sets <= j)173 num_option_sets = j + 1;174 }175 }176 }177 }178 179 if (num_option_sets > 0) {180 m_required_options.resize(num_option_sets);181 m_optional_options.resize(num_option_sets);182 183 for (const auto &def : opt_defs) {184 for (uint32_t j = 0; j < num_option_sets; j++) {185 if (def.usage_mask & 1 << j) {186 if (def.required)187 m_required_options[j].insert(def.short_option);188 else189 m_optional_options[j].insert(def.short_option);190 }191 }192 }193 }194}195 196uint32_t Options::NumCommandOptions() { return GetDefinitions().size(); }197 198Option *Options::GetLongOptions() {199 // Check to see if this has already been done.200 if (m_getopt_table.empty()) {201 auto defs = GetDefinitions();202 if (defs.empty())203 return nullptr;204 205 std::map<int, uint32_t> option_seen;206 207 m_getopt_table.resize(defs.size() + 1);208 for (size_t i = 0; i < defs.size(); ++i) {209 const int short_opt = defs[i].short_option;210 211 m_getopt_table[i].definition = &defs[i];212 m_getopt_table[i].flag = nullptr;213 m_getopt_table[i].val = short_opt;214 215 auto [pos, inserted] = option_seen.try_emplace(short_opt, i);216 if (!inserted && short_opt) {217 m_getopt_table[i].val = 0;218 StreamString strm;219 if (defs[i].HasShortOption())220 Debugger::ReportError(221 llvm::formatv(222 "option[{0}] --{1} has a short option -{2} that "223 "conflicts with option[{3}] --{4}, short option won't "224 "be used for --{5}",225 i, defs[i].long_option, short_opt, pos->second,226 m_getopt_table[pos->second].definition->long_option,227 defs[i].long_option)228 .str());229 else230 Debugger::ReportError(231 llvm::formatv(232 "option[{0}] --{1} has a short option {2:x} that "233 "conflicts with option[{3}] --{4}, short option won't "234 "be used for --{5}",235 (int)i, defs[i].long_option, short_opt, pos->second,236 m_getopt_table[pos->second].definition->long_option,237 defs[i].long_option)238 .str());239 }240 }241 242 // getopt_long_only requires a NULL final entry in the table:243 244 m_getopt_table.back().definition = nullptr;245 m_getopt_table.back().flag = nullptr;246 m_getopt_table.back().val = 0;247 }248 249 if (m_getopt_table.empty())250 return nullptr;251 252 return &m_getopt_table.front();253}254 255// This function takes INDENT, which tells how many spaces to output at the256// front of each line; SPACES, which is a string containing 80 spaces; and257// TEXT, which is the text that is to be output. It outputs the text, on258// multiple lines if necessary, to RESULT, with INDENT spaces at the front of259// each line. It breaks lines on spaces, tabs or newlines, shortening the line260// if necessary to not break in the middle of a word. It assumes that each261// output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.262 263void Options::OutputFormattedUsageText(Stream &strm,264 const OptionDefinition &option_def,265 uint32_t output_max_columns,266 bool use_color) {267 std::string actual_text;268 if (option_def.validator) {269 const char *condition = option_def.validator->ShortConditionString();270 if (condition) {271 actual_text = "[";272 actual_text.append(condition);273 actual_text.append("] ");274 }275 }276 actual_text.append(277 ansi::FormatAnsiTerminalCodes(option_def.usage_text, use_color));278 const size_t visible_length = ansi::ColumnWidth(actual_text);279 280 // Will it all fit on one line?281 282 if (static_cast<uint32_t>(visible_length + strm.GetIndentLevel()) <283 output_max_columns) {284 // Output it as a single line.285 strm.Indent(ansi::FormatAnsiTerminalCodes(actual_text, use_color));286 strm.EOL();287 } else {288 // We need to break it up into multiple lines.289 290 int text_width = output_max_columns - strm.GetIndentLevel() - 1;291 int start = 0;292 int end = start;293 int final_end = visible_length;294 int sub_len;295 296 while (end < final_end) {297 // Don't start the 'text' on a space, since we're already outputting the298 // indentation.299 while ((start < final_end) && (actual_text[start] == ' '))300 start++;301 302 end = start + text_width;303 if (end > final_end)304 end = final_end;305 else {306 // If we're not at the end of the text, make sure we break the line on307 // white space.308 while (end > start && actual_text[end] != ' ' &&309 actual_text[end] != '\t' && actual_text[end] != '\n')310 end--;311 }312 313 sub_len = end - start;314 if (start != 0)315 strm.EOL();316 strm.Indent();317 assert(start < final_end);318 assert(start + sub_len <= final_end);319 strm.PutCString(ansi::FormatAnsiTerminalCodes(320 llvm::StringRef(actual_text.c_str() + start, sub_len), use_color));321 start = end + 1;322 }323 strm.EOL();324 }325}326 327bool Options::SupportsLongOption(const char *long_option) {328 if (!long_option || !long_option[0])329 return false;330 331 auto opt_defs = GetDefinitions();332 if (opt_defs.empty())333 return false;334 335 const char *long_option_name = long_option;336 if (long_option[0] == '-' && long_option[1] == '-')337 long_option_name += 2;338 339 for (auto &def : opt_defs) {340 if (!def.long_option)341 continue;342 343 if (strcmp(def.long_option, long_option_name) == 0)344 return true;345 }346 347 return false;348}349 350enum OptionDisplayType {351 eDisplayBestOption,352 eDisplayShortOption,353 eDisplayLongOption354};355 356static bool PrintOption(const OptionDefinition &opt_def,357 OptionDisplayType display_type, const char *header,358 const char *footer, bool show_optional, Stream &strm) {359 if (display_type == eDisplayShortOption && !opt_def.HasShortOption())360 return false;361 362 if (header && header[0])363 strm.PutCString(header);364 365 if (show_optional && !opt_def.required)366 strm.PutChar('[');367 const bool show_short_option =368 opt_def.HasShortOption() && display_type != eDisplayLongOption;369 if (show_short_option)370 strm.Printf("-%c", opt_def.short_option);371 else372 strm.Printf("--%s", opt_def.long_option);373 switch (opt_def.option_has_arg) {374 case OptionParser::eNoArgument:375 break;376 case OptionParser::eRequiredArgument:377 strm.Printf(" <%s>", CommandObject::GetArgumentName(opt_def.argument_type));378 break;379 380 case OptionParser::eOptionalArgument:381 strm.Printf("%s[<%s>]", show_short_option ? "" : "=",382 CommandObject::GetArgumentName(opt_def.argument_type));383 break;384 }385 if (show_optional && !opt_def.required)386 strm.PutChar(']');387 if (footer && footer[0])388 strm.PutCString(footer);389 return true;390}391 392void Options::GenerateOptionUsage(Stream &strm, CommandObject &cmd,393 uint32_t screen_width, bool use_color) {394 auto opt_defs = GetDefinitions();395 const uint32_t save_indent_level = strm.GetIndentLevel();396 llvm::StringRef name = cmd.GetCommandName();397 StreamString arguments_str;398 cmd.GetFormattedCommandArguments(arguments_str);399 400 const uint32_t num_options = NumCommandOptions();401 if (num_options == 0)402 return;403 404 const bool only_print_args = cmd.IsDashDashCommand();405 if (!only_print_args)406 strm.PutCString("\nCommand Options Usage:\n");407 408 strm.IndentMore(2);409 410 // First, show each usage level set of options, e.g. <cmd> [options-for-411 // level-0]412 // <cmd>413 // [options-for-level-1]414 // etc.415 416 if (!only_print_args) {417 uint32_t num_option_sets = GetRequiredOptions().size();418 for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) {419 if (opt_set > 0)420 strm.Printf("\n");421 strm.Indent(name);422 423 // Different option sets may require different args.424 StreamString args_str;425 uint32_t opt_set_mask = 1 << opt_set;426 cmd.GetFormattedCommandArguments(args_str, opt_set_mask);427 428 // First go through and print all options that take no arguments as a429 // single string. If a command has "-a" "-b" and "-c", this will show up430 // as [-abc]431 432 // We use a set here so that they will be sorted.433 std::set<int> required_options;434 std::set<int> optional_options;435 436 for (auto &def : opt_defs) {437 if (def.usage_mask & opt_set_mask && def.HasShortOption() &&438 def.option_has_arg == OptionParser::eNoArgument) {439 if (def.required) {440 required_options.insert(def.short_option);441 } else {442 optional_options.insert(def.short_option);443 }444 }445 }446 447 if (!required_options.empty()) {448 strm.PutCString(" -");449 for (int short_option : required_options)450 strm.PutChar(short_option);451 }452 453 if (!optional_options.empty()) {454 strm.PutCString(" [-");455 for (int short_option : optional_options)456 strm.PutChar(short_option);457 strm.PutChar(']');458 }459 460 // First go through and print the required options (list them up front).461 for (auto &def : opt_defs) {462 if (def.usage_mask & opt_set_mask && def.HasShortOption() &&463 def.required && def.option_has_arg != OptionParser::eNoArgument)464 PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm);465 }466 467 // Now go through again, and this time only print the optional options.468 for (auto &def : opt_defs) {469 if (def.usage_mask & opt_set_mask && !def.required &&470 def.option_has_arg != OptionParser::eNoArgument)471 PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm);472 }473 474 if (args_str.GetSize() > 0) {475 if (cmd.WantsRawCommandString())476 strm.Printf(" --");477 strm << " " << args_str.GetString();478 }479 }480 }481 482 if ((only_print_args || cmd.WantsRawCommandString()) &&483 arguments_str.GetSize() > 0) {484 if (!only_print_args)485 strm.PutChar('\n');486 strm.Indent(name);487 strm << " " << arguments_str.GetString();488 }489 490 if (!only_print_args) {491 strm.Printf("\n\n");492 493 // Now print out all the detailed information about the various options:494 // long form, short form and help text:495 // -short <argument> ( --long_name <argument> )496 // help text497 498 strm.IndentMore(5);499 500 // Put the command options in a sorted container, so we can output501 // them alphabetically by short_option.502 std::multimap<int, uint32_t> options_ordered;503 for (auto def : llvm::enumerate(opt_defs))504 options_ordered.insert(505 std::make_pair(def.value().short_option, def.index()));506 507 // Go through each option, find the table entry and write out the detailed508 // help information for that option.509 510 bool first_option_printed = false;511 512 for (auto pos : options_ordered) {513 // Put a newline separation between arguments514 if (first_option_printed)515 strm.EOL();516 else517 first_option_printed = true;518 519 OptionDefinition opt_def = opt_defs[pos.second];520 521 strm.Indent();522 if (opt_def.short_option && opt_def.HasShortOption()) {523 PrintOption(opt_def, eDisplayShortOption, nullptr, nullptr, false,524 strm);525 PrintOption(opt_def, eDisplayLongOption, " ( ", " )", false, strm);526 } else {527 // Short option is not printable, just print long option528 PrintOption(opt_def, eDisplayLongOption, nullptr, nullptr, false, strm);529 }530 strm.EOL();531 532 strm.IndentMore(5);533 534 if (opt_def.usage_text)535 OutputFormattedUsageText(strm, opt_def, screen_width, use_color);536 if (!opt_def.enum_values.empty()) {537 strm.Indent();538 strm.Printf("Values: ");539 bool is_first = true;540 for (const auto &enum_value : opt_def.enum_values) {541 if (is_first) {542 strm.Printf("%s", enum_value.string_value);543 is_first = false;544 }545 else546 strm.Printf(" | %s", enum_value.string_value);547 }548 strm.EOL();549 }550 strm.IndentLess(5);551 }552 }553 554 // Restore the indent level555 strm.SetIndentLevel(save_indent_level);556}557 558llvm::Error Options::VerifyOptions() {559 bool options_are_valid = false;560 561 int num_levels = GetRequiredOptions().size();562 if (num_levels) {563 for (int i = 0; i < num_levels && !options_are_valid; ++i) {564 // This is the correct set of options if: 1). m_seen_options contains565 // all of m_required_options[i] (i.e. all the required options at this566 // level are a subset of m_seen_options); AND 2). { m_seen_options -567 // m_required_options[i] is a subset of m_options_options[i] (i.e. all568 // the rest of m_seen_options are in the set of optional options at this569 // level.570 571 // Check to see if all of m_required_options[i] are a subset of572 // m_seen_options573 if (IsASubset(GetRequiredOptions()[i], m_seen_options)) {574 // Construct the set difference: remaining_options = {m_seen_options} -575 // {m_required_options[i]}576 OptionSet remaining_options;577 OptionsSetDiff(m_seen_options, GetRequiredOptions()[i],578 remaining_options);579 // Check to see if remaining_options is a subset of580 // m_optional_options[i]581 if (IsASubset(remaining_options, GetOptionalOptions()[i]))582 options_are_valid = true;583 }584 }585 } else {586 options_are_valid = true;587 }588 589 if (!options_are_valid)590 return llvm::createStringError(591 "invalid combination of options for the given command");592 593 return llvm::Error::success();594}595 596// This function is called when we have been given a potentially incomplete set597// of options, such as when an alias has been defined (more options might be598// added at at the time the alias is invoked). We need to verify that the599// options in the set m_seen_options are all part of a set that may be used600// together, but m_seen_options may be missing some of the "required" options.601llvm::Error Options::VerifyPartialOptions() {602 bool options_are_valid = false;603 604 int num_levels = GetRequiredOptions().size();605 if (num_levels) {606 for (int i = 0; i < num_levels && !options_are_valid; ++i) {607 // In this case we are treating all options as optional rather than608 // required. Therefore a set of options is correct if m_seen_options is a609 // subset of the union of m_required_options and m_optional_options.610 OptionSet union_set;611 OptionsSetUnion(GetRequiredOptions()[i], GetOptionalOptions()[i],612 union_set);613 if (IsASubset(m_seen_options, union_set))614 options_are_valid = true;615 }616 }617 618 if (!options_are_valid)619 return llvm::createStringError(620 "invalid combination of options for the given command");621 622 return llvm::Error::success();623}624 625bool Options::HandleOptionCompletion(CompletionRequest &request,626 OptionElementVector &opt_element_vector,627 CommandInterpreter &interpreter) {628 // For now we just scan the completions to see if the cursor position is in629 // an option or its argument. Otherwise we'll call HandleArgumentCompletion.630 // In the future we can use completion to validate options as well if we631 // want.632 633 auto opt_defs = GetDefinitions();634 635 llvm::StringRef cur_opt_str = request.GetCursorArgumentPrefix();636 const bool use_color = interpreter.GetDebugger().GetUseColor();637 638 for (size_t i = 0; i < opt_element_vector.size(); i++) {639 size_t opt_pos = static_cast<size_t>(opt_element_vector[i].opt_pos);640 size_t opt_arg_pos = static_cast<size_t>(opt_element_vector[i].opt_arg_pos);641 int opt_defs_index = opt_element_vector[i].opt_defs_index;642 if (opt_pos == request.GetCursorIndex()) {643 // We're completing the option itself.644 645 if (opt_defs_index == OptionArgElement::eBareDash) {646 // We're completing a bare dash. That means all options are open.647 // FIXME: We should scan the other options provided and only complete648 // options649 // within the option group they belong to.650 std::string opt_str = "-a";651 652 for (auto &def : opt_defs) {653 if (!def.short_option)654 continue;655 opt_str[1] = def.short_option;656 request.AddCompletion(opt_str, ansi::FormatAnsiTerminalCodes(657 def.usage_text, use_color));658 }659 660 return true;661 } else if (opt_defs_index == OptionArgElement::eBareDoubleDash) {662 std::string full_name("--");663 for (auto &def : opt_defs) {664 if (!def.short_option)665 continue;666 667 full_name.erase(full_name.begin() + 2, full_name.end());668 full_name.append(def.long_option);669 request.AddCompletion(full_name, ansi::FormatAnsiTerminalCodes(670 def.usage_text, use_color));671 }672 return true;673 } else if (opt_defs_index != OptionArgElement::eUnrecognizedArg) {674 // We recognized it, if it an incomplete long option, complete it675 // anyway (getopt_long_only is happy with shortest unique string, but676 // it's still a nice thing to do.) Otherwise return The string so the677 // upper level code will know this is a full match and add the " ".678 const OptionDefinition &opt = opt_defs[opt_defs_index];679 llvm::StringRef long_option = opt.long_option;680 if (cur_opt_str.starts_with("--") && cur_opt_str != long_option) {681 request.AddCompletion(682 "--" + long_option.str(),683 ansi::FormatAnsiTerminalCodes(opt.usage_text, use_color));684 return true;685 } else686 request.AddCompletion(request.GetCursorArgumentPrefix());687 return true;688 } else {689 // FIXME - not handling wrong options yet:690 // Check to see if they are writing a long option & complete it.691 // I think we will only get in here if the long option table has two692 // elements693 // that are not unique up to this point. getopt_long_only does694 // shortest unique match for long options already.695 if (cur_opt_str.consume_front("--")) {696 for (auto &def : opt_defs) {697 llvm::StringRef long_option(def.long_option);698 if (long_option.starts_with(cur_opt_str))699 request.AddCompletion(700 "--" + long_option.str(),701 ansi::FormatAnsiTerminalCodes(def.usage_text, use_color));702 }703 }704 return true;705 }706 707 } else if (opt_arg_pos == request.GetCursorIndex()) {708 // Okay the cursor is on the completion of an argument. See if it has a709 // completion, otherwise return no matches. Note, opt_defs_index == -1710 // means we're after an option, but that option doesn't exist. We'll711 // end up treating that as an argument. Not sure we can do much better.712 if (opt_defs_index != -1) {713 HandleOptionArgumentCompletion(request, opt_element_vector, i,714 interpreter);715 return true;716 } else {717 // No completion callback means no completions...718 return true;719 }720 721 } else {722 // Not the last element, keep going.723 continue;724 }725 }726 return false;727}728 729void Options::HandleOptionArgumentCompletion(730 CompletionRequest &request, OptionElementVector &opt_element_vector,731 int opt_element_index, CommandInterpreter &interpreter) {732 auto opt_defs = GetDefinitions();733 std::unique_ptr<SearchFilter> filter_up;734 735 int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;736 737 // See if this is an enumeration type option, and if so complete it here:738 const auto &enum_values = opt_defs[opt_defs_index].enum_values;739 if (!enum_values.empty())740 for (const auto &enum_value : enum_values)741 request.TryCompleteCurrentArg(enum_value.string_value);742 743 // If this is a source file or symbol type completion, and there is a -shlib744 // option somewhere in the supplied arguments, then make a search filter for745 // that shared library.746 // FIXME: Do we want to also have an "OptionType" so we don't have to match747 // string names?748 749 uint32_t completion_mask = opt_defs[opt_defs_index].completion_type;750 751 if (completion_mask == 0) {752 lldb::CommandArgumentType option_arg_type =753 opt_defs[opt_defs_index].argument_type;754 if (option_arg_type != eArgTypeNone) {755 const CommandObject::ArgumentTableEntry *arg_entry =756 CommandObject::FindArgumentDataByType(757 opt_defs[opt_defs_index].argument_type);758 if (arg_entry)759 completion_mask = arg_entry->completion_type;760 }761 }762 763 if (completion_mask & lldb::eSourceFileCompletion ||764 completion_mask & lldb::eSymbolCompletion) {765 for (size_t i = 0; i < opt_element_vector.size(); i++) {766 int cur_defs_index = opt_element_vector[i].opt_defs_index;767 768 // trying to use <0 indices will definitely cause problems769 if (cur_defs_index == OptionArgElement::eUnrecognizedArg ||770 cur_defs_index == OptionArgElement::eBareDash ||771 cur_defs_index == OptionArgElement::eBareDoubleDash)772 continue;773 774 int cur_arg_pos = opt_element_vector[i].opt_arg_pos;775 const char *cur_opt_name = opt_defs[cur_defs_index].long_option;776 777 // If this is the "shlib" option and there was an argument provided,778 // restrict it to that shared library.779 if (cur_opt_name && strcmp(cur_opt_name, "shlib") == 0 &&780 cur_arg_pos != -1) {781 const char *module_name =782 request.GetParsedLine().GetArgumentAtIndex(cur_arg_pos);783 if (module_name) {784 FileSpec module_spec(module_name);785 lldb::TargetSP target_sp =786 interpreter.GetDebugger().GetSelectedTarget();787 // Search filters require a target...788 if (target_sp)789 filter_up =790 std::make_unique<SearchFilterByModule>(target_sp, module_spec);791 }792 break;793 }794 }795 }796 797 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(798 interpreter, completion_mask, request, filter_up.get());799}800 801void OptionGroupOptions::Append(OptionGroup *group) {802 auto group_option_defs = group->GetDefinitions();803 for (uint32_t i = 0; i < group_option_defs.size(); ++i) {804 m_option_infos.push_back(OptionInfo(group, i));805 m_option_defs.push_back(group_option_defs[i]);806 }807}808 809const OptionGroup *OptionGroupOptions::GetGroupWithOption(char short_opt) {810 for (uint32_t i = 0; i < m_option_defs.size(); i++) {811 OptionDefinition opt_def = m_option_defs[i];812 if (opt_def.short_option == short_opt)813 return m_option_infos[i].option_group;814 }815 return nullptr;816}817 818void OptionGroupOptions::Append(OptionGroup *group, uint32_t src_mask,819 uint32_t dst_mask) {820 auto group_option_defs = group->GetDefinitions();821 for (uint32_t i = 0; i < group_option_defs.size(); ++i) {822 if (group_option_defs[i].usage_mask & src_mask) {823 m_option_infos.push_back(OptionInfo(group, i));824 m_option_defs.push_back(group_option_defs[i]);825 m_option_defs.back().usage_mask = dst_mask;826 }827 }828}829 830void OptionGroupOptions::Append(831 OptionGroup *group, llvm::ArrayRef<llvm::StringRef> exclude_long_options) {832 auto group_option_defs = group->GetDefinitions();833 for (uint32_t i = 0; i < group_option_defs.size(); ++i) {834 const auto &definition = group_option_defs[i];835 if (llvm::is_contained(exclude_long_options, definition.long_option))836 continue;837 838 m_option_infos.push_back(OptionInfo(group, i));839 m_option_defs.push_back(definition);840 }841}842 843void OptionGroupOptions::Finalize() {844 m_did_finalize = true;845}846 847Status OptionGroupOptions::SetOptionValue(uint32_t option_idx,848 llvm::StringRef option_value,849 ExecutionContext *execution_context) {850 // After calling OptionGroupOptions::Append(...), you must finalize the851 // groups by calling OptionGroupOptions::Finlize()852 assert(m_did_finalize);853 Status error;854 if (option_idx < m_option_infos.size()) {855 error = m_option_infos[option_idx].option_group->SetOptionValue(856 m_option_infos[option_idx].option_index, option_value,857 execution_context);858 859 } else {860 error =861 Status::FromErrorString("invalid option index"); // Shouldn't happen...862 }863 return error;864}865 866void OptionGroupOptions::OptionParsingStarting(867 ExecutionContext *execution_context) {868 std::set<OptionGroup *> group_set;869 OptionInfos::iterator pos, end = m_option_infos.end();870 for (pos = m_option_infos.begin(); pos != end; ++pos) {871 OptionGroup *group = pos->option_group;872 if (group_set.find(group) == group_set.end()) {873 group->OptionParsingStarting(execution_context);874 group_set.insert(group);875 }876 }877}878Status879OptionGroupOptions::OptionParsingFinished(ExecutionContext *execution_context) {880 std::set<OptionGroup *> group_set;881 Status error;882 OptionInfos::iterator pos, end = m_option_infos.end();883 for (pos = m_option_infos.begin(); pos != end; ++pos) {884 OptionGroup *group = pos->option_group;885 if (group_set.find(group) == group_set.end()) {886 error = group->OptionParsingFinished(execution_context);887 group_set.insert(group);888 if (error.Fail())889 return error;890 }891 }892 return error;893}894 895// OptionParser permutes the arguments while processing them, so we create a896// temporary array holding to avoid modification of the input arguments. The897// options themselves are never modified, but the API expects a char * anyway,898// hence the const_cast.899static std::vector<char *> GetArgvForParsing(const Args &args) {900 std::vector<char *> result;901 // OptionParser always skips the first argument as it is based on getopt().902 result.push_back(const_cast<char *>("<FAKE-ARG0>"));903 for (const Args::ArgEntry &entry : args)904 result.push_back(const_cast<char *>(entry.c_str()));905 result.push_back(nullptr);906 return result;907}908 909// Given a permuted argument, find it's position in the original Args vector.910static Args::const_iterator FindOriginalIter(const char *arg,911 const Args &original) {912 return llvm::find_if(913 original, [arg](const Args::ArgEntry &D) { return D.c_str() == arg; });914}915 916// Given a permuted argument, find it's index in the original Args vector.917static size_t FindOriginalIndex(const char *arg, const Args &original) {918 return std::distance(original.begin(), FindOriginalIter(arg, original));919}920 921// Construct a new Args object, consisting of the entries from the original922// arguments, but in the permuted order.923static Args ReconstituteArgsAfterParsing(llvm::ArrayRef<char *> parsed,924 const Args &original) {925 Args result;926 for (const char *arg : parsed) {927 auto pos = FindOriginalIter(arg, original);928 assert(pos != original.end());929 result.AppendArgument(pos->ref(), pos->GetQuoteChar());930 }931 return result;932}933 934static size_t FindArgumentIndexForOption(const Args &args,935 const Option &long_option) {936 std::string short_opt = llvm::formatv("-{0}", char(long_option.val)).str();937 std::string long_opt =938 std::string(llvm::formatv("--{0}", long_option.definition->long_option));939 for (const auto &entry : llvm::enumerate(args)) {940 if (entry.value().ref().starts_with(short_opt) ||941 entry.value().ref().starts_with(long_opt))942 return entry.index();943 }944 945 return size_t(-1);946}947 948static std::string BuildShortOptions(const Option *long_options) {949 std::string storage;950 llvm::raw_string_ostream sstr(storage);951 952 // Leading : tells getopt to return a : for a missing option argument AND to953 // suppress error messages.954 sstr << ":";955 956 for (size_t i = 0; long_options[i].definition != nullptr; ++i) {957 if (long_options[i].flag == nullptr) {958 sstr << (char)long_options[i].val;959 switch (long_options[i].definition->option_has_arg) {960 default:961 case OptionParser::eNoArgument:962 break;963 case OptionParser::eRequiredArgument:964 sstr << ":";965 break;966 case OptionParser::eOptionalArgument:967 sstr << "::";968 break;969 }970 }971 }972 return storage;973}974 975llvm::Expected<Args> Options::ParseAlias(const Args &args,976 OptionArgVector *option_arg_vector,977 std::string &input_line) {978 Option *long_options = GetLongOptions();979 980 if (long_options == nullptr) {981 return llvm::createStringError("Invalid long options");982 }983 984 std::string short_options = BuildShortOptions(long_options);985 986 Args args_copy = args;987 std::vector<char *> argv = GetArgvForParsing(args);988 989 std::unique_lock<std::mutex> lock;990 OptionParser::Prepare(lock);991 int val;992 while (true) {993 int long_options_index = -1;994 val = OptionParser::Parse(argv, short_options, long_options,995 &long_options_index);996 997 if (val == ':') {998 return llvm::createStringError(llvm::inconvertibleErrorCode(),999 "last option requires an argument");1000 }1001 1002 if (val == -1)1003 break;1004 1005 if (val == '?') {1006 return llvm::createStringError("Unknown or ambiguous option");1007 }1008 1009 if (val == 0)1010 continue;1011 1012 OptionSeen(val);1013 1014 // Look up the long option index1015 if (long_options_index == -1) {1016 for (int j = 0; long_options[j].definition || long_options[j].flag ||1017 long_options[j].val;1018 ++j) {1019 if (long_options[j].val == val) {1020 long_options_index = j;1021 break;1022 }1023 }1024 }1025 1026 // See if the option takes an argument, and see if one was supplied.1027 if (long_options_index == -1) {1028 return llvm::createStringError(1029 llvm::formatv("Invalid option with value '{0}'.", char(val)).str());1030 }1031 1032 StreamString option_str;1033 option_str.Printf("-%c", val);1034 const OptionDefinition *def = long_options[long_options_index].definition;1035 int has_arg =1036 (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;1037 1038 const char *option_arg = nullptr;1039 switch (has_arg) {1040 case OptionParser::eRequiredArgument:1041 if (OptionParser::GetOptionArgument() == nullptr) {1042 return llvm::createStringError(1043 llvm::formatv("Option '{0}' is missing argument specifier.",1044 option_str.GetString())1045 .str());1046 }1047 [[fallthrough]];1048 case OptionParser::eOptionalArgument:1049 option_arg = OptionParser::GetOptionArgument();1050 [[fallthrough]];1051 case OptionParser::eNoArgument:1052 break;1053 default:1054 return llvm::createStringError(1055 llvm::formatv("error with options table; invalid value in has_arg "1056 "field for option '{0}'.",1057 char(val))1058 .str());1059 }1060 // Find option in the argument list; also see if it was supposed to take an1061 // argument and if one was supplied. Remove option (and argument, if1062 // given) from the argument list. Also remove them from the1063 // raw_input_string, if one was passed in.1064 // Note: We also need to preserve any option argument values that were1065 // surrounded by backticks, as we lose track of them in the1066 // option_args_vector.1067 size_t idx =1068 FindArgumentIndexForOption(args_copy, long_options[long_options_index]);1069 std::string option_to_insert;1070 if (option_arg) {1071 if (idx != size_t(-1) && has_arg) {1072 bool arg_has_backtick = args_copy[idx + 1].GetQuoteChar() == '`';1073 if (arg_has_backtick)1074 option_to_insert = "`";1075 option_to_insert += option_arg;1076 if (arg_has_backtick)1077 option_to_insert += "`";1078 } else1079 option_to_insert = option_arg;1080 } else1081 option_to_insert = CommandInterpreter::g_no_argument;1082 1083 option_arg_vector->emplace_back(std::string(option_str.GetString()),1084 has_arg, option_to_insert);1085 1086 if (idx == size_t(-1))1087 continue;1088 1089 if (!input_line.empty()) {1090 llvm::StringRef tmp_arg = args_copy[idx].ref();1091 size_t pos = input_line.find(tmp_arg);1092 if (pos != std::string::npos)1093 input_line.erase(pos, tmp_arg.size());1094 }1095 args_copy.DeleteArgumentAtIndex(idx);1096 if ((option_to_insert != CommandInterpreter::g_no_argument) &&1097 (OptionParser::GetOptionArgument() != nullptr) &&1098 (idx < args_copy.GetArgumentCount()) &&1099 (args_copy[idx].ref() == OptionParser::GetOptionArgument())) {1100 if (input_line.size() > 0) {1101 size_t pos = input_line.find(option_to_insert);1102 if (pos != std::string::npos)1103 input_line.erase(pos, option_to_insert.size());1104 }1105 args_copy.DeleteArgumentAtIndex(idx);1106 }1107 }1108 1109 return std::move(args_copy);1110}1111 1112OptionElementVector Options::ParseForCompletion(const Args &args,1113 uint32_t cursor_index) {1114 OptionElementVector option_element_vector;1115 Option *long_options = GetLongOptions();1116 option_element_vector.clear();1117 1118 if (long_options == nullptr)1119 return option_element_vector;1120 1121 std::string short_options = BuildShortOptions(long_options);1122 1123 std::unique_lock<std::mutex> lock;1124 OptionParser::Prepare(lock);1125 OptionParser::EnableError(false);1126 1127 int val;1128 auto opt_defs = GetDefinitions();1129 1130 std::vector<char *> dummy_vec = GetArgvForParsing(args);1131 1132 bool failed_once = false;1133 uint32_t dash_dash_pos = -1;1134 1135 while (true) {1136 bool missing_argument = false;1137 int long_options_index = -1;1138 1139 val = OptionParser::Parse(dummy_vec, short_options, long_options,1140 &long_options_index);1141 1142 if (val == -1) {1143 // When we're completing a "--" which is the last option on line,1144 if (failed_once)1145 break;1146 1147 failed_once = true;1148 1149 // If this is a bare "--" we mark it as such so we can complete it1150 // successfully later. Handling the "--" is a little tricky, since that1151 // may mean end of options or arguments, or the user might want to1152 // complete options by long name. I make this work by checking whether1153 // the cursor is in the "--" argument, and if so I assume we're1154 // completing the long option, otherwise I let it pass to1155 // OptionParser::Parse which will terminate the option parsing. Note, in1156 // either case we continue parsing the line so we can figure out what1157 // other options were passed. This will be useful when we come to1158 // restricting completions based on what other options we've seen on the1159 // line.1160 1161 if (static_cast<size_t>(OptionParser::GetOptionIndex()) <1162 dummy_vec.size() &&1163 (strcmp(dummy_vec[OptionParser::GetOptionIndex() - 1], "--") == 0)) {1164 dash_dash_pos = FindOriginalIndex(1165 dummy_vec[OptionParser::GetOptionIndex() - 1], args);1166 if (dash_dash_pos == cursor_index) {1167 option_element_vector.push_back(1168 OptionArgElement(OptionArgElement::eBareDoubleDash, dash_dash_pos,1169 OptionArgElement::eBareDoubleDash));1170 continue;1171 } else1172 break;1173 } else1174 break;1175 } else if (val == '?') {1176 option_element_vector.push_back(OptionArgElement(1177 OptionArgElement::eUnrecognizedArg,1178 FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],1179 args),1180 OptionArgElement::eUnrecognizedArg));1181 continue;1182 } else if (val == 0) {1183 continue;1184 } else if (val == ':') {1185 // This is a missing argument.1186 val = OptionParser::GetOptionErrorCause();1187 missing_argument = true;1188 }1189 1190 OptionSeen(val);1191 1192 // Look up the long option index1193 if (long_options_index == -1) {1194 for (int j = 0; long_options[j].definition || long_options[j].flag ||1195 long_options[j].val;1196 ++j) {1197 if (long_options[j].val == val) {1198 long_options_index = j;1199 break;1200 }1201 }1202 }1203 1204 // See if the option takes an argument, and see if one was supplied.1205 if (long_options_index >= 0) {1206 int opt_defs_index = -1;1207 for (size_t i = 0; i < opt_defs.size(); i++) {1208 if (opt_defs[i].short_option != val)1209 continue;1210 opt_defs_index = i;1211 break;1212 }1213 1214 const OptionDefinition *def = long_options[long_options_index].definition;1215 int has_arg =1216 (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;1217 switch (has_arg) {1218 case OptionParser::eNoArgument:1219 option_element_vector.push_back(OptionArgElement(1220 opt_defs_index,1221 FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],1222 args),1223 0));1224 break;1225 case OptionParser::eRequiredArgument:1226 if (OptionParser::GetOptionArgument() != nullptr) {1227 int arg_index;1228 if (missing_argument)1229 arg_index = -1;1230 else1231 arg_index = OptionParser::GetOptionIndex() - 2;1232 1233 option_element_vector.push_back(OptionArgElement(1234 opt_defs_index,1235 FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],1236 args),1237 arg_index));1238 } else {1239 option_element_vector.push_back(OptionArgElement(1240 opt_defs_index,1241 FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],1242 args),1243 -1));1244 }1245 break;1246 case OptionParser::eOptionalArgument:1247 option_element_vector.push_back(OptionArgElement(1248 opt_defs_index,1249 FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],1250 args),1251 FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],1252 args)));1253 break;1254 default:1255 // The options table is messed up. Here we'll just continue1256 option_element_vector.push_back(OptionArgElement(1257 OptionArgElement::eUnrecognizedArg,1258 FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],1259 args),1260 OptionArgElement::eUnrecognizedArg));1261 break;1262 }1263 } else {1264 option_element_vector.push_back(OptionArgElement(1265 OptionArgElement::eUnrecognizedArg,1266 FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],1267 args),1268 OptionArgElement::eUnrecognizedArg));1269 }1270 }1271 1272 // Finally we have to handle the case where the cursor index points at a1273 // single "-". We want to mark that in the option_element_vector, but only1274 // if it is not after the "--". But it turns out that OptionParser::Parse1275 // just ignores an isolated "-". So we have to look it up by hand here. We1276 // only care if it is AT the cursor position. Note, a single quoted dash is1277 // not the same as a single dash...1278 1279 const Args::ArgEntry &cursor = args[cursor_index];1280 if ((static_cast<int32_t>(dash_dash_pos) == -1 ||1281 cursor_index < dash_dash_pos) &&1282 !cursor.IsQuoted() && cursor.ref() == "-") {1283 option_element_vector.push_back(1284 OptionArgElement(OptionArgElement::eBareDash, cursor_index,1285 OptionArgElement::eBareDash));1286 }1287 return option_element_vector;1288}1289 1290llvm::Expected<Args> Options::Parse(const Args &args,1291 ExecutionContext *execution_context,1292 lldb::PlatformSP platform_sp,1293 bool require_validation) {1294 Status error;1295 Option *long_options = GetLongOptions();1296 if (long_options == nullptr) {1297 return llvm::createStringError("invalid long options");1298 }1299 1300 std::string short_options = BuildShortOptions(long_options);1301 std::vector<char *> argv = GetArgvForParsing(args);1302 1303 std::unique_lock<std::mutex> lock;1304 OptionParser::Prepare(lock);1305 while (true) {1306 int long_options_index = -1;1307 int val = OptionParser::Parse(argv, short_options, long_options,1308 &long_options_index);1309 1310 if (val == ':') {1311 error = Status::FromErrorString("last option requires an argument");1312 break;1313 }1314 1315 if (val == -1)1316 break;1317 1318 // Did we get an error?1319 if (val == '?') {1320 // Account for "argv[0]" and that it points to the next option.1321 int idx = OptionParser::GetOptionIndex() - 2;1322 if (idx >= 0 && (size_t)idx < args.GetArgumentCount())1323 error = Status::FromError(llvm::make_error<OptionParseError>(1324 args[idx], "unknown or ambiguous option"));1325 else1326 error = Status("unknown or ambiguous option");1327 1328 break;1329 }1330 // The option auto-set itself1331 if (val == 0)1332 continue;1333 1334 OptionSeen(val);1335 1336 // Lookup the long option index1337 if (long_options_index == -1) {1338 for (int i = 0; long_options[i].definition || long_options[i].flag ||1339 long_options[i].val;1340 ++i) {1341 if (long_options[i].val == val) {1342 long_options_index = i;1343 break;1344 }1345 }1346 }1347 // Call the callback with the option1348 if (long_options_index >= 0 &&1349 long_options[long_options_index].definition) {1350 const OptionDefinition *def = long_options[long_options_index].definition;1351 1352 if (!platform_sp) {1353 // User did not pass in an explicit platform. Try to grab from the1354 // execution context.1355 TargetSP target_sp =1356 execution_context ? execution_context->GetTargetSP() : TargetSP();1357 platform_sp = target_sp ? target_sp->GetPlatform() : PlatformSP();1358 }1359 OptionValidator *validator = def->validator;1360 1361 if (!platform_sp && require_validation) {1362 // Caller requires validation but we cannot validate as we don't have1363 // the mandatory platform against which to validate.1364 return llvm::createStringError(1365 "cannot validate options: no platform available");1366 }1367 1368 bool validation_failed = false;1369 if (platform_sp) {1370 // Ensure we have an execution context, empty or not.1371 ExecutionContext dummy_context;1372 ExecutionContext *exe_ctx_p =1373 execution_context ? execution_context : &dummy_context;1374 if (validator && !validator->IsValid(*platform_sp, *exe_ctx_p)) {1375 validation_failed = true;1376 error = Status::FromErrorStringWithFormat(1377 "Option \"%s\" invalid. %s", def->long_option,1378 def->validator->LongConditionString());1379 }1380 }1381 1382 // As long as validation didn't fail, we set the option value.1383 if (!validation_failed)1384 error =1385 SetOptionValue(long_options_index,1386 (def->option_has_arg == OptionParser::eNoArgument)1387 ? nullptr1388 : OptionParser::GetOptionArgument(),1389 execution_context);1390 // If the Option setting returned an error, we should stop parsing1391 // and return the error.1392 if (error.Fail())1393 break;1394 } else {1395 error = Status::FromErrorStringWithFormat(1396 "invalid option with value '%i'", val);1397 }1398 }1399 1400 if (error.Fail())1401 return error.ToError();1402 1403 argv.pop_back();1404 argv.erase(argv.begin(), argv.begin() + OptionParser::GetOptionIndex());1405 return ReconstituteArgsAfterParsing(argv, args);1406}1407 1408llvm::Error lldb_private::CreateOptionParsingError(1409 llvm::StringRef option_arg, const char short_option,1410 llvm::StringRef long_option, llvm::StringRef additional_context) {1411 std::string buffer;1412 llvm::raw_string_ostream stream(buffer);1413 stream << "Invalid value ('" << option_arg << "') for -" << short_option;1414 if (!long_option.empty())1415 stream << " (" << long_option << ")";1416 if (!additional_context.empty())1417 stream << ": " << additional_context;1418 return llvm::createStringError(llvm::inconvertibleErrorCode(), buffer);1419}1420