1 //===-- OptionGroupFormat.cpp -----------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Interpreter/OptionGroupFormat.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Core/ArchSpec.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Target/ExecutionContext.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Utility/Utils.h"
21 
22 using namespace lldb;
23 using namespace lldb_private;
24 
25 OptionGroupFormat::OptionGroupFormat(lldb::Format default_format,
26                                      uint64_t default_byte_size,
27                                      uint64_t default_count)
28     : m_format(default_format, default_format),
29       m_byte_size(default_byte_size, default_byte_size),
30       m_count(default_count, default_count), m_prev_gdb_format('x'),
31       m_prev_gdb_size('w') {}
32 
33 OptionGroupFormat::~OptionGroupFormat() {}
34 
35 static OptionDefinition g_option_table[] = {
36     {LLDB_OPT_SET_1, false, "format", 'f', OptionParser::eRequiredArgument,
37      nullptr, nullptr, 0, eArgTypeFormat,
38      "Specify a format to be used for display."},
39     {LLDB_OPT_SET_2, false, "gdb-format", 'G', OptionParser::eRequiredArgument,
40      nullptr, nullptr, 0, eArgTypeGDBFormat,
41      "Specify a format using a GDB format specifier string."},
42     {LLDB_OPT_SET_3, false, "size", 's', OptionParser::eRequiredArgument,
43      nullptr, nullptr, 0, eArgTypeByteSize,
44      "The size in bytes to use when displaying with the selected format."},
45     {LLDB_OPT_SET_4, false, "count", 'c', OptionParser::eRequiredArgument,
46      nullptr, nullptr, 0, eArgTypeCount,
47      "The number of total items to display."},
48 };
49 
50 llvm::ArrayRef<OptionDefinition> OptionGroupFormat::GetDefinitions() {
51   llvm::ArrayRef<OptionDefinition> result = g_option_table;
52   if (m_byte_size.GetDefaultValue() < UINT64_MAX) {
53     if (m_count.GetDefaultValue() < UINT64_MAX)
54       return result;
55     else
56       return result.take_front(3);
57   }
58   return result.take_front(2);
59 }
60 
61 Error OptionGroupFormat::SetOptionValue(uint32_t option_idx,
62                                         const char *option_arg,
63                                         ExecutionContext *execution_context) {
64   Error error;
65   const int short_option = g_option_table[option_idx].short_option;
66 
67   switch (short_option) {
68   case 'f':
69     error = m_format.SetValueFromString(option_arg);
70     break;
71 
72   case 'c':
73     if (m_count.GetDefaultValue() == 0) {
74       error.SetErrorString("--count option is disabled");
75     } else {
76       error = m_count.SetValueFromString(option_arg);
77       if (m_count.GetCurrentValue() == 0)
78         error.SetErrorStringWithFormat("invalid --count option value '%s'",
79                                        option_arg);
80     }
81     break;
82 
83   case 's':
84     if (m_byte_size.GetDefaultValue() == 0) {
85       error.SetErrorString("--size option is disabled");
86     } else {
87       error = m_byte_size.SetValueFromString(option_arg);
88       if (m_byte_size.GetCurrentValue() == 0)
89         error.SetErrorStringWithFormat("invalid --size option value '%s'",
90                                        option_arg);
91     }
92     break;
93 
94   case 'G': {
95     char *end = nullptr;
96     const char *gdb_format_cstr = option_arg;
97     uint64_t count = 0;
98     if (::isdigit(gdb_format_cstr[0])) {
99       count = strtoull(gdb_format_cstr, &end, 0);
100 
101       if (option_arg != end)
102         gdb_format_cstr =
103             end; // We have a valid count, advance the string position
104       else
105         count = 0;
106     }
107 
108     Format format = eFormatDefault;
109     uint32_t byte_size = 0;
110 
111     while (ParserGDBFormatLetter(execution_context, gdb_format_cstr[0], format,
112                                  byte_size)) {
113       ++gdb_format_cstr;
114     }
115 
116     // We the first character of the "gdb_format_cstr" is not the
117     // NULL terminator, we didn't consume the entire string and
118     // something is wrong. Also, if none of the format, size or count
119     // was specified correctly, then abort.
120     if (gdb_format_cstr[0] ||
121         (format == eFormatInvalid && byte_size == 0 && count == 0)) {
122       // Nothing got set correctly
123       error.SetErrorStringWithFormat("invalid gdb format string '%s'",
124                                      option_arg);
125       return error;
126     }
127 
128     // At least one of the format, size or count was set correctly.
129     // Anything that wasn't set correctly should be set to the
130     // previous default
131     if (format == eFormatInvalid)
132       ParserGDBFormatLetter(execution_context, m_prev_gdb_format, format,
133                             byte_size);
134 
135     const bool byte_size_enabled = m_byte_size.GetDefaultValue() < UINT64_MAX;
136     const bool count_enabled = m_count.GetDefaultValue() < UINT64_MAX;
137     if (byte_size_enabled) {
138       // Byte size is enabled
139       if (byte_size == 0)
140         ParserGDBFormatLetter(execution_context, m_prev_gdb_size, format,
141                               byte_size);
142     } else {
143       // Byte size is disabled, make sure it wasn't specified
144       // but if this is an address, it's actually necessary to
145       // 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     error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
180     break;
181   }
182 
183   return error;
184 }
185 
186 bool OptionGroupFormat::ParserGDBFormatLetter(
187     ExecutionContext *execution_context, char format_letter, Format &format,
188     uint32_t &byte_size) {
189   m_has_gdb_format = true;
190   switch (format_letter) {
191   case 'o':
192     format = eFormatOctal;
193     m_prev_gdb_format = format_letter;
194     return true;
195   case 'x':
196     format = eFormatHex;
197     m_prev_gdb_format = format_letter;
198     return true;
199   case 'd':
200     format = eFormatDecimal;
201     m_prev_gdb_format = format_letter;
202     return true;
203   case 'u':
204     format = eFormatUnsigned;
205     m_prev_gdb_format = format_letter;
206     return true;
207   case 't':
208     format = eFormatBinary;
209     m_prev_gdb_format = format_letter;
210     return true;
211   case 'f':
212     format = eFormatFloat;
213     m_prev_gdb_format = format_letter;
214     return true;
215   case 'a':
216     format = eFormatAddressInfo;
217     {
218       TargetSP target_sp =
219           execution_context ? execution_context->GetTargetSP() : TargetSP();
220       if (target_sp)
221         byte_size = target_sp->GetArchitecture().GetAddressByteSize();
222       m_prev_gdb_format = format_letter;
223       return true;
224     }
225   case 'i':
226     format = eFormatInstruction;
227     m_prev_gdb_format = format_letter;
228     return true;
229   case 'c':
230     format = eFormatChar;
231     m_prev_gdb_format = format_letter;
232     return true;
233   case 's':
234     format = eFormatCString;
235     m_prev_gdb_format = format_letter;
236     return true;
237   case 'T':
238     format = eFormatOSType;
239     m_prev_gdb_format = format_letter;
240     return true;
241   case 'A':
242     format = eFormatHexFloat;
243     m_prev_gdb_format = format_letter;
244     return true;
245 
246   // Size isn't used for printing instructions, so if a size is specified, and
247   // the previous format was
248   // 'i', then we should reset it to the default ('x').  Otherwise we'll
249   // continue to print as instructions,
250   // which isn't expected.
251   case 'b':
252     byte_size = 1;
253     LLVM_FALLTHROUGH;
254   case 'h':
255     byte_size = 2;
256     LLVM_FALLTHROUGH;
257   case 'w':
258     byte_size = 4;
259     LLVM_FALLTHROUGH;
260   case '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   return false;
273 }
274 
275 void OptionGroupFormat::OptionParsingStarting(
276     ExecutionContext *execution_context) {
277   m_format.Clear();
278   m_byte_size.Clear();
279   m_count.Clear();
280   m_has_gdb_format = false;
281 }
282