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