xref: /freebsd/contrib/llvm-project/lldb/source/Interpreter/OptionGroupFormat.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1  //===-- OptionGroupFormat.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  //===----------------------------------------------------------------------===//
8  
9  #include "lldb/Interpreter/OptionGroupFormat.h"
10  
11  #include "lldb/Host/OptionParser.h"
12  #include "lldb/Interpreter/CommandInterpreter.h"
13  #include "lldb/Target/ExecutionContext.h"
14  #include "lldb/Target/Target.h"
15  
16  using namespace lldb;
17  using namespace lldb_private;
18  
19  static constexpr OptionDefinition g_default_option_definitions[] = {
20      {LLDB_OPT_SET_1, false, "format", 'f', OptionParser::eRequiredArgument,
21       nullptr, {}, 0, eArgTypeFormat,
22       "Specify a format to be used for display."},
23      {LLDB_OPT_SET_2, false, "gdb-format", 'G', OptionParser::eRequiredArgument,
24       nullptr, {}, 0, eArgTypeGDBFormat,
25       "Specify a format using a GDB format specifier string."},
26      {LLDB_OPT_SET_3, false, "size", 's', OptionParser::eRequiredArgument,
27       nullptr, {}, 0, eArgTypeByteSize,
28       "The size in bytes to use when displaying with the selected format."},
29      {LLDB_OPT_SET_4, false, "count", 'c', OptionParser::eRequiredArgument,
30       nullptr, {}, 0, eArgTypeCount,
31       "The number of total items to display."},
32  };
33  
OptionGroupFormat(lldb::Format default_format,uint64_t default_byte_size,uint64_t default_count,OptionGroupFormatUsageTextVector usage_text_vector)34  OptionGroupFormat::OptionGroupFormat(
35      lldb::Format default_format, uint64_t default_byte_size,
36      uint64_t default_count, OptionGroupFormatUsageTextVector usage_text_vector)
37      : m_format(default_format, default_format),
38        m_byte_size(default_byte_size, default_byte_size),
39        m_count(default_count, default_count), m_prev_gdb_format('x'),
40        m_prev_gdb_size('w'), m_has_gdb_format(false) {
41    // Copy the default option definitions.
42    std::copy(std::begin(g_default_option_definitions),
43              std::end(g_default_option_definitions),
44              std::begin(m_option_definitions));
45  
46    for (auto usage_text_tuple : usage_text_vector) {
47      switch (std::get<0>(usage_text_tuple)) {
48      case eArgTypeFormat:
49        m_option_definitions[0].usage_text = std::get<1>(usage_text_tuple);
50        break;
51      case eArgTypeByteSize:
52        m_option_definitions[2].usage_text = std::get<1>(usage_text_tuple);
53        break;
54      default:
55        llvm_unreachable("Unimplemented option");
56      }
57    }
58  }
59  
GetDefinitions()60  llvm::ArrayRef<OptionDefinition> OptionGroupFormat::GetDefinitions() {
61    auto result = llvm::ArrayRef(m_option_definitions);
62    if (m_byte_size.GetDefaultValue() < UINT64_MAX) {
63      if (m_count.GetDefaultValue() < UINT64_MAX)
64        return result;
65      else
66        return result.take_front(3);
67    }
68    return result.take_front(2);
69  }
70  
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)71  Status OptionGroupFormat::SetOptionValue(uint32_t option_idx,
72                                           llvm::StringRef option_arg,
73                                           ExecutionContext *execution_context) {
74    Status error;
75    const int short_option = m_option_definitions[option_idx].short_option;
76  
77    switch (short_option) {
78    case 'f':
79      error = m_format.SetValueFromString(option_arg);
80      break;
81  
82    case 'c':
83      if (m_count.GetDefaultValue() == 0) {
84        error.SetErrorString("--count option is disabled");
85      } else {
86        error = m_count.SetValueFromString(option_arg);
87        if (m_count.GetCurrentValue() == 0)
88          error.SetErrorStringWithFormat("invalid --count option value '%s'",
89                                         option_arg.str().c_str());
90      }
91      break;
92  
93    case 's':
94      if (m_byte_size.GetDefaultValue() == 0) {
95        error.SetErrorString("--size option is disabled");
96      } else {
97        error = m_byte_size.SetValueFromString(option_arg);
98        if (m_byte_size.GetCurrentValue() == 0)
99          error.SetErrorStringWithFormat("invalid --size option value '%s'",
100                                         option_arg.str().c_str());
101      }
102      break;
103  
104    case 'G': {
105      uint64_t count = 0;
106      llvm::StringRef gdb_format_str = option_arg;
107      gdb_format_str.consumeInteger(0, count);
108  
109      Format format = eFormatDefault;
110      uint32_t byte_size = 0;
111  
112      while (!gdb_format_str.empty() &&
113             ParserGDBFormatLetter(execution_context, gdb_format_str[0], format,
114                                   byte_size)) {
115        gdb_format_str = gdb_format_str.drop_front();
116      }
117  
118      // We the first character of the "gdb_format_str" is not the
119      // NULL terminator, we didn't consume the entire string and
120      // something is wrong. Also, if none of the format, size or count was
121      // specified correctly, then abort.
122      if (!gdb_format_str.empty() ||
123          (format == eFormatInvalid && byte_size == 0 && count == 0)) {
124        // Nothing got set correctly
125        error.SetErrorStringWithFormat("invalid gdb format string '%s'",
126                                       option_arg.str().c_str());
127        return error;
128      }
129  
130      // At least one of the format, size or count was set correctly. Anything
131      // that wasn't set correctly should be set to the previous default
132      if (format == eFormatInvalid)
133        ParserGDBFormatLetter(execution_context, m_prev_gdb_format, format,
134                              byte_size);
135  
136      const bool byte_size_enabled = m_byte_size.GetDefaultValue() < UINT64_MAX;
137      const bool count_enabled = m_count.GetDefaultValue() < UINT64_MAX;
138      if (byte_size_enabled) {
139        // Byte size is enabled
140        if (byte_size == 0)
141          ParserGDBFormatLetter(execution_context, m_prev_gdb_size, format,
142                                byte_size);
143      } else {
144        // Byte size is disabled, make sure it wasn't specified but if this is an
145        // address, it's actually necessary to specify one so don't error out
146        if (byte_size > 0 && format != lldb::eFormatAddressInfo) {
147          error.SetErrorString(
148              "this command doesn't support specifying a byte size");
149          return error;
150        }
151      }
152  
153      if (count_enabled) {
154        // Count is enabled and was not set, set it to the default for gdb format
155        // statements (which is 1).
156        if (count == 0)
157          count = 1;
158      } else {
159        // Count is disabled, make sure it wasn't specified
160        if (count > 0) {
161          error.SetErrorString("this command doesn't support specifying a count");
162          return error;
163        }
164      }
165  
166      m_format.SetCurrentValue(format);
167      m_format.SetOptionWasSet();
168      if (byte_size_enabled) {
169        m_byte_size.SetCurrentValue(byte_size);
170        m_byte_size.SetOptionWasSet();
171      }
172      if (count_enabled) {
173        m_count.SetCurrentValue(count);
174        m_count.SetOptionWasSet();
175      }
176    } break;
177  
178    default:
179      llvm_unreachable("Unimplemented option");
180    }
181  
182    return error;
183  }
184  
ParserGDBFormatLetter(ExecutionContext * execution_context,char format_letter,Format & format,uint32_t & byte_size)185  bool OptionGroupFormat::ParserGDBFormatLetter(
186      ExecutionContext *execution_context, char format_letter, Format &format,
187      uint32_t &byte_size) {
188    m_has_gdb_format = true;
189    switch (format_letter) {
190    case 'o':
191      format = eFormatOctal;
192      m_prev_gdb_format = format_letter;
193      return true;
194    case 'x':
195      format = eFormatHex;
196      m_prev_gdb_format = format_letter;
197      return true;
198    case 'd':
199      format = eFormatDecimal;
200      m_prev_gdb_format = format_letter;
201      return true;
202    case 'u':
203      format = eFormatUnsigned;
204      m_prev_gdb_format = format_letter;
205      return true;
206    case 't':
207      format = eFormatBinary;
208      m_prev_gdb_format = format_letter;
209      return true;
210    case 'f':
211      format = eFormatFloat;
212      m_prev_gdb_format = format_letter;
213      return true;
214    case 'a':
215      format = eFormatAddressInfo;
216      {
217        TargetSP target_sp =
218            execution_context ? execution_context->GetTargetSP() : TargetSP();
219        if (target_sp)
220          byte_size = target_sp->GetArchitecture().GetAddressByteSize();
221        m_prev_gdb_format = format_letter;
222        return true;
223      }
224    case 'i':
225      format = eFormatInstruction;
226      m_prev_gdb_format = format_letter;
227      return true;
228    case 'c':
229      format = eFormatChar;
230      m_prev_gdb_format = format_letter;
231      return true;
232    case 's':
233      format = eFormatCString;
234      m_prev_gdb_format = format_letter;
235      return true;
236    case 'T':
237      format = eFormatOSType;
238      m_prev_gdb_format = format_letter;
239      return true;
240    case 'A':
241      format = eFormatHexFloat;
242      m_prev_gdb_format = format_letter;
243      return true;
244  
245    case 'b':
246    case 'h':
247    case 'w':
248    case 'g':
249      {
250        // Size isn't used for printing instructions, so if a size is specified,
251        // and the previous format was 'i', then we should reset it to the
252        // default ('x').  Otherwise we'll continue to print as instructions,
253        // which isn't expected.
254        if (format_letter == 'b')
255            byte_size = 1;
256        else if (format_letter == 'h')
257            byte_size = 2;
258        else if (format_letter == 'w')
259            byte_size = 4;
260        else if (format_letter == 'g')
261            byte_size = 8;
262  
263          m_prev_gdb_size = format_letter;
264          if (m_prev_gdb_format == 'i')
265            m_prev_gdb_format = 'x';
266          return true;
267      }
268      break;
269    default:
270      break;
271    }
272  
273  
274    return false;
275  }
276  
OptionParsingStarting(ExecutionContext * execution_context)277  void OptionGroupFormat::OptionParsingStarting(
278      ExecutionContext *execution_context) {
279    m_format.Clear();
280    m_byte_size.Clear();
281    m_count.Clear();
282    m_has_gdb_format = false;
283  }
284