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 uint32_t OptionGroupFormat::GetNumDefinitions() {
51   if (m_byte_size.GetDefaultValue() < UINT64_MAX) {
52     if (m_count.GetDefaultValue() < UINT64_MAX)
53       return 4;
54     else
55       return 3;
56   }
57   return 2;
58 }
59 
60 const OptionDefinition *OptionGroupFormat::GetDefinitions() {
61   return g_option_table;
62 }
63 
64 Error OptionGroupFormat::SetOptionValue(uint32_t option_idx,
65                                         const char *option_arg,
66                                         ExecutionContext *execution_context) {
67   Error error;
68   const int short_option = g_option_table[option_idx].short_option;
69 
70   switch (short_option) {
71   case 'f':
72     error = m_format.SetValueFromString(option_arg);
73     break;
74 
75   case 'c':
76     if (m_count.GetDefaultValue() == 0) {
77       error.SetErrorString("--count option is disabled");
78     } else {
79       error = m_count.SetValueFromString(option_arg);
80       if (m_count.GetCurrentValue() == 0)
81         error.SetErrorStringWithFormat("invalid --count option value '%s'",
82                                        option_arg);
83     }
84     break;
85 
86   case 's':
87     if (m_byte_size.GetDefaultValue() == 0) {
88       error.SetErrorString("--size option is disabled");
89     } else {
90       error = m_byte_size.SetValueFromString(option_arg);
91       if (m_byte_size.GetCurrentValue() == 0)
92         error.SetErrorStringWithFormat("invalid --size option value '%s'",
93                                        option_arg);
94     }
95     break;
96 
97   case 'G': {
98     char *end = nullptr;
99     const char *gdb_format_cstr = option_arg;
100     uint64_t count = 0;
101     if (::isdigit(gdb_format_cstr[0])) {
102       count = strtoull(gdb_format_cstr, &end, 0);
103 
104       if (option_arg != end)
105         gdb_format_cstr =
106             end; // We have a valid count, advance the string position
107       else
108         count = 0;
109     }
110 
111     Format format = eFormatDefault;
112     uint32_t byte_size = 0;
113 
114     while (ParserGDBFormatLetter(execution_context, gdb_format_cstr[0], format,
115                                  byte_size)) {
116       ++gdb_format_cstr;
117     }
118 
119     // We the first character of the "gdb_format_cstr" is not the
120     // NULL terminator, we didn't consume the entire string and
121     // something is wrong. Also, if none of the format, size or count
122     // was specified correctly, then abort.
123     if (gdb_format_cstr[0] ||
124         (format == eFormatInvalid && byte_size == 0 && count == 0)) {
125       // Nothing got set correctly
126       error.SetErrorStringWithFormat("invalid gdb format string '%s'",
127                                      option_arg);
128       return error;
129     }
130 
131     // At least one of the format, size or count was set correctly.
132     // Anything that wasn't set correctly should be set to the
133     // previous default
134     if (format == eFormatInvalid)
135       ParserGDBFormatLetter(execution_context, m_prev_gdb_format, format,
136                             byte_size);
137 
138     const bool byte_size_enabled = m_byte_size.GetDefaultValue() < UINT64_MAX;
139     const bool count_enabled = m_count.GetDefaultValue() < UINT64_MAX;
140     if (byte_size_enabled) {
141       // Byte size is enabled
142       if (byte_size == 0)
143         ParserGDBFormatLetter(execution_context, m_prev_gdb_size, format,
144                               byte_size);
145     } else {
146       // Byte size is disabled, make sure it wasn't specified
147       // but if this is an address, it's actually necessary to
148       // specify one so don't error out
149       if (byte_size > 0 && format != lldb::eFormatAddressInfo) {
150         error.SetErrorString(
151             "this command doesn't support specifying a byte size");
152         return error;
153       }
154     }
155 
156     if (count_enabled) {
157       // Count is enabled and was not set, set it to the default for gdb format
158       // statements (which is 1).
159       if (count == 0)
160         count = 1;
161     } else {
162       // Count is disabled, make sure it wasn't specified
163       if (count > 0) {
164         error.SetErrorString("this command doesn't support specifying a count");
165         return error;
166       }
167     }
168 
169     m_format.SetCurrentValue(format);
170     m_format.SetOptionWasSet();
171     if (byte_size_enabled) {
172       m_byte_size.SetCurrentValue(byte_size);
173       m_byte_size.SetOptionWasSet();
174     }
175     if (count_enabled) {
176       m_count.SetCurrentValue(count);
177       m_count.SetOptionWasSet();
178     }
179   } break;
180 
181   default:
182     error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
183     break;
184   }
185 
186   return error;
187 }
188 
189 bool OptionGroupFormat::ParserGDBFormatLetter(
190     ExecutionContext *execution_context, char format_letter, Format &format,
191     uint32_t &byte_size) {
192   m_has_gdb_format = true;
193   switch (format_letter) {
194   case 'o':
195     format = eFormatOctal;
196     m_prev_gdb_format = format_letter;
197     return true;
198   case 'x':
199     format = eFormatHex;
200     m_prev_gdb_format = format_letter;
201     return true;
202   case 'd':
203     format = eFormatDecimal;
204     m_prev_gdb_format = format_letter;
205     return true;
206   case 'u':
207     format = eFormatUnsigned;
208     m_prev_gdb_format = format_letter;
209     return true;
210   case 't':
211     format = eFormatBinary;
212     m_prev_gdb_format = format_letter;
213     return true;
214   case 'f':
215     format = eFormatFloat;
216     m_prev_gdb_format = format_letter;
217     return true;
218   case 'a':
219     format = eFormatAddressInfo;
220     {
221       TargetSP target_sp =
222           execution_context ? execution_context->GetTargetSP() : TargetSP();
223       if (target_sp)
224         byte_size = target_sp->GetArchitecture().GetAddressByteSize();
225       m_prev_gdb_format = format_letter;
226       return true;
227     }
228   case 'i':
229     format = eFormatInstruction;
230     m_prev_gdb_format = format_letter;
231     return true;
232   case 'c':
233     format = eFormatChar;
234     m_prev_gdb_format = format_letter;
235     return true;
236   case 's':
237     format = eFormatCString;
238     m_prev_gdb_format = format_letter;
239     return true;
240   case 'T':
241     format = eFormatOSType;
242     m_prev_gdb_format = format_letter;
243     return true;
244   case 'A':
245     format = eFormatHexFloat;
246     m_prev_gdb_format = format_letter;
247     return true;
248 
249   // Size isn't used for printing instructions, so if a size is specified, and
250   // the previous format was
251   // 'i', then we should reset it to the default ('x').  Otherwise we'll
252   // continue to print as instructions,
253   // which isn't expected.
254   case 'b':
255     byte_size = 1;
256     LLVM_FALLTHROUGH;
257   case 'h':
258     byte_size = 2;
259     LLVM_FALLTHROUGH;
260   case 'w':
261     byte_size = 4;
262     LLVM_FALLTHROUGH;
263   case 'g':
264     byte_size = 8;
265 
266     m_prev_gdb_size = format_letter;
267     if (m_prev_gdb_format == 'i')
268       m_prev_gdb_format = 'x';
269     return true;
270 
271     break;
272   default:
273     break;
274   }
275   return false;
276 }
277 
278 void OptionGroupFormat::OptionParsingStarting(
279     ExecutionContext *execution_context) {
280   m_format.Clear();
281   m_byte_size.Clear();
282   m_count.Clear();
283   m_has_gdb_format = false;
284 }
285